1

私はテーブルを持っています:

名前 | データ | アイテム
数 1 | 16 | 2
アイテム2 | 17 | 3
アイテム1 | 16 | 5

私はそれを次のように変換したいと思います:

{ item1: {16+16, 2+5}, item2: {17, 3}}

ただし、次の結果しか生成できません。

{ item1: 16+16, item2: 17}

次のコードを使用: Stats クラスには両方のフィールドが保存されますが、両方のフィールドをデータに追加する方法がわかりません

class Stats {
    public Integer data, num;
    public Stats(Integer td, Integer nf) {
        data = td;
        num = nf;
    }
    public Integer getdata(){
        return data;
    }
    public Integer getnum(){
        return num;
    }
}
Map<String, Stats> map = new HashMap<>();
Stream<String> lines = Files.lines(Paths.get(table));
map = lines.map(x -> 
             .collect(Collectors.toMap(
                z -> z[0],
                z -> Integer.parseInt(z[1]),
                (a, b) -> a+b));

上記のコードはMap<String, Int>、どのように機能するかわからないため、のみ機能しMap<String, Stats>ます。1 つのパイプラインのみを使用しながら、2 番目の列のアイテムをマップに取得する方法はありますか?

4

3 に答える 3

1

まず、2 つの整数を含むクラスを作成する必要があります。

public final class TwoInts {
    private final int data;
    private final int num;

    public TwoInts(int data, int num) { 
        this.data = data;
        this.num = num;
    }

    // getters omitted for brevity
}

次に、整数を使用する代わりに TwoInts インスタンスを使用することを除いて、既にあるロジックを再利用できます。したがって、TwoInts の 2 つのインスタンスを一緒に追加して、別の TwoInts インスタンスを生成できる必要があります (2 つの整数を追加して新しい整数を生成するのと同じように)。

public final class TwoInts {
    private final int data;
    private final int num;

    public TwoInts(int data, int num) { 
        this.data = data;
        this.num = num;
    }

    public static TwoInts sum(TwoInts first, TwoInts second) {
        return new TwoInts(first.data + second.data, 
                           first.num + second.num);
    }

    // getters omitted for brevity
}

そして、そこに行きます:

Stream<String> lines = Files.lines(Paths.get(table));
Map<String, TwoInts> map = 
    lines.map(line -> toArrayOfStrings(line))
         .collect(Collectors.toMap(
              row -> row[0],
              row -> new TwoInts(Integer.parseInt(row[1]), Integer.parseInt(row[2])),
              (a, b) -> TwoInts.sum(a, b));
于 2015-04-21T22:59:34.363 に答える
0

最初に、マージ メソッドを追加して Stats クラスをもう少し削減フレンドリーにすることができます (私も少しきれいにしました)。

class Stats {
    final int data, num;

    public Stats() {
        data = num = 0;
    }

    public Stats(int data, int num) {
        this.data = data;
        this.num = num;
    }

    public Stats merge(Stats stats) {
        return new Stats(this.data+stats.data, this.num+stats.num);
    }

    public int getData(){
        return data;
    }
    public int getNum(){
        return num;
    }

    @Override
    public String toString() {
        return "{" + data + "," + num + "}";
    }
}

これで、一連のコレクターを使用してタスクを解決できます。ボヘミアンの回答のように、入力が文字列ストリームから来ているとします。

Stream<String> lines = Stream.of("item1,16,2",
          "item2,17,3",
          "item1,16,5"); // sample input

結果のマップは、次の方法で構築できます。

Map<String, Stats> map = lines.map(s -> s.split(",")).collect(
    Collectors.groupingBy(a -> a[0], 
    Collectors.mapping(a -> new Stats(Integer.parseInt(a[1]), Integer.parseInt(a[2])), 
    Collectors.reducing(new Stats(), Stats::merge))));
System.out.println(map);

ライブデモはこちら.

于 2015-05-02T06:46:41.307 に答える
0

これが次の実装です。

  • 追加のクラスは必要ありません
  • 任意の長さの数値 (2 だけでなく) に対して機能します
  • (技術的に)たった1行です


Stream<String> lines = Stream.of("item1,16,2",
      "item2,17,3",
      "item1,16,5"); // sample input

Map<String, List<Integer>> map = lines.map(s -> s.split(","))
  .collect(Collectors.toMap(a -> a[0],
      a -> Arrays.asList(a).stream()
       .skip(1).map(Integer::parseInt)
        .collect(Collectors.toList()),
      (a, b) -> {for (int i = 0; i < a.size(); i++)
          a.set(i, a.get(i) + b.get(i)); return a;}));

この出力を実行した後にマップを印刷します。

{item2=[17, 3], item1=[32, 7]}

このコードのライブ デモを参照してください。

于 2015-04-23T23:14:12.257 に答える