2016-06-29 9 views
1

私は日付とブールエラーインジケータを持つオブジェクトプロセスを持っています。私は、各プロセスの合計数とエラーのあるプロセスの数を各日付ごとに取得したいと考えています。したがって、例えばJunの場合、カウントは2,1です。 6月2日は1、0、6月3日1、1があります。これを行うには、2回ストリーミングしてカウントを取得するしかありません。私はカスタムコレクタを実装しようとしましたが、成功していません。私のkludgyメソッドの代わりにエレガントなソリューションがありますか?Java 8ストリームgroupbyと複数のプロパティをカウント

final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 
    final List<Process> processes = new ArrayList<>(); 
    processes.add(new Process(sdf.parse("2016-06-01"), false)); 
    processes.add(new Process(sdf.parse("2016-06-01"), true)); 
    processes.add(new Process(sdf.parse("2016-06-02"), false)); 
    processes.add(new Process(sdf.parse("2016-06-03"), true)); 

    System.out.println(processes.stream() 
      .collect(
        Collectors.groupingBy(Process::getDate, Collectors.counting()))); 

    System.out.println(processes.stream().filter(order -> order.isHasError()) 
       .collect(
         Collectors.groupingBy(Process::getDate, Collectors.counting()))); 

private class Process { 
    private Date date; 
    private boolean hasError; 

    public Process(Date date, boolean hasError) { 
     this.date = date; 
     this.hasError = hasError; 
    } 

    public Date getDate() { 
     return date; 
    } 

    public boolean isHasError() { 
     return hasError; 
    } 
} 

コードソリューションの@ glee8e後とホルガーのヒント@

Collector<Process, Result, Result> ProcessCollector = Collector.of(
     () -> Result::new, 
     (r, p) -> { 
      r.increment(0); 
      if (p.isHasError()) { 
       r.increment(1); 
      } 
     }, (r1, r2) -> { 
      r1.add(0, r2.get(0)); 
      r1.add(1, r2.get(1)); 
      return r1; 
}); 

Map<Date, Result> results = Processs.stream().collect(groupingBy(Process::getDate, ProcessCollector)); 
results.entrySet().stream().sorted(Comparator.comparing(Entry::getKey)).forEach(entry -> System.out 
     .println(String.format("date = %s, %s", sdf.format(entry.getKey()), entry.getValue()))); 



private class Result { 

    private AtomicIntegerArray array = new AtomicIntegerArray(2); 

    public int get(int index) { 
     return array.get(index); 
    } 

    public void increment(int index) { 
     array.getAndIncrement(index); 
    } 

    public void add(int index, int delta) { 
     array.addAndGet(index, delta); 
    } 

    @Override 
    public String toString() { 
     return String.format("totalProcesses = %d, totalErrors = %d", array.get(0), array.get(1)); 
    } 
} 
+0

を持っていると仮定します。 – bphilipnyc

答えて

4

我々は結果を格納するPOJOを追加したり、コンバイナ機能5月は少しあいまいに見えることが好ましいです。私はPOJOを公開して宣言しましたが、それを隠す方が良いと思えば変更できます。

public class Result { 
    public int all, error; 
} 

メインコード:

// Add it somewhere in this file. 
private static final Set <Characteristics> CH_ID = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH)); 

//... 
// This is main processing code 
processes.stream().collect(collectingAndThen(groupingBy(Process::getDate, new Collector<Process, Result, Result> { 
      @Override 
      public Supplier<Result> supplier() { 
       return Result::new; 
      } 

      @Override 
      public BiConsumer<Process, Result> accumlator() { 
       return (p, r) -> { 
        r.total++; 
        if (p.isHasError()) 
         r.error++; 
       }; 
      } 

      @Override 
      public BinaryOperator<Result> combiner() { 
       return (r1, r2) -> { 
        r1.total += r2.total; 
        r1.error += r2.error; 
        return r1; 
       }; 
      } 

      @Override 
      public Function<Result, Result> finisher() { 
       return Function.identity(); 
      } 

      @Override 
      public Set<Characteristics> characteristics() { 
       return CH_ID; 
      } 
}))); 

PS:私はあなたがまた、あなたの2行目に `Collection`にList``からタイプを弱めることができimport static java.util.stream.Collectors

+0

ありがとうglee8e。あなたのソリューションは、真/偽のカウントを提供します。私は合計とエラーの数を取得するために探していた。だから、6月1日には、それは私に1を与えます。私はラムダ式の外でそれを合計して合計を得ることができると思います。しかし、私は本当に表現の中でそれをやろうとしていました。 – golfradio

+0

@golfradioが更新されました。コードはちょっと醜いように見える... – glee8e

+2

['Collector.of(...)']の存在を気にする](https://docs.oracle.com/javase/8/docs/api/java/util/stream/ Collector.html#of-java.util.function.Supplier-java.util.function.BiConsumer-java.util.function.BinaryOperator-java.util.stream.Collector.Characteristics ...-)これにより、内部クラスを必要とせずに3つの関数(IDフィニッシャを省略)あなたは 'IDENTITY_FINISH'特性を指定することを悩ます必要もなく、そのメソッドはそのような関数が存在しないことから既にそれを推論します。しかし、あなたは 'UNORDERED'特性を指定することを検討するかもしれません... – Holger

関連する問題