読者です 読者をやめる 読者になる 読者になる

リスト順のままのグルーピングカウント

リストをキーによってカウントする=グルーピングしてカウントするのに変な要求の題を突き付けられました。
例えば、以下のようなクラスのObjectのリスト、(内部にカウンタを持ちグルーピングカウントの結果を持つもの)とします。

public class Item{
   public int id;
   public String name;
   public int count;
   public Item(int id, String name){
      this.id = id;
      this.name = name;
   }
   @Override
   public String toString(){
      return "id=" + id + "  name=" + name + "  count="+count;
   }
}

これに対して、作成した List 以下のように作成したとして、、、

List<Item> list = new ArrayList<>();
list.add(new Item(1, "a"));
list.add(new Item(2, "a"));
list.add(new Item(3, "b"));
list.add(new Item(4, "b"));
list.add(new Item(5, "c"));
list.add(new Item(6, "a"));
list.add(new Item(7, "a"));

を グルーピングカウントして、Stream などで、

   list.stream().forEach(System.out::println);

の結果を、

id=1  name=a  count=4
id=2  name=a  count=0
id=3  name=b  count=2
id=4  name=b  count=0
id=5  name=c  count=1
id=6  name=a  count=0
id=7  name=a  count=0

ではなくて、、、リスト順にカウントして

id=1  name=a  count=2
id=2  name=a  count=0
id=3  name=b  count=2
id=4  name=b  count=0
id=5  name=c  count=1
id=6  name=a  count=2
id=7  name=a  count=0

のリストになるように、リストを作りなおしたいという変な結果を求める要求を突き付けられました。

困ったもので、悩んだあげく key と index と count を持つ次のようなクラスを用意して、、

public final class Meter implements Serializable{
   private String key;
   private int index;
   private int count;
   public Meter(){}
   // key, index, count 各々の setter, getter を用意
}

リストに対して、なんともクレイジーなコードを書くことになりました。

AtomicInteger index = new AtomicInteger(0);
Meter meter = new Meter();
list.stream().forEach(e->{
   int ix = index.getAndIncrement();
   if (meter.getCount()==0){
      meter.setKey(e.name);
      meter.setIndex(ix);
      meter.setCount(1);
   }else{
      if (meter.getKey().equals(e.name)){
         meter.setCount(meter.getCount()+1);
      }else{
         Item item = list.get(meter.getIndex());
         item.count = meter.getCount();
         list.set(meter.getIndex(), item);
         meter.setKey(e.name);
         meter.setIndex(ix);
         meter.setCount(1);
      }
   }
});
Item item = list.get(meter.getIndex());
item.count = meter.getCount();
list.set(meter.getIndex(), item);
list.stream().forEach(System.out::println);

の結果が、目的どおりにはなったけど、、こういう結果を求める仕様に釈然としません。