Java 8 流如何将 2 列映射到映射中



我有一个表格:

名称 | 数据 | 编号
项目1 |16 |阿拉伯数字
项目2 |17 |
3 项目1 |16 |5

我想将其转换为:

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

但是,我只能成功产生以下结果:

{ 项目1: 16+16, 项目2: 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 个管道时将第二列上的项目放入地图吗?

首先需要创建一个包含两个整数的类:

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 的两个实例加在一起以生成另一个 TwoInts 实例(就像通过添加两个整数来生成新整数一样):

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));

下面是一个实现:

  • 不需要任何额外的课程
  • 适用于任意长度的数值(不仅仅是 2)
  • (技术上)只是一行


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]}

查看此代码的现场演示。

首先,您可以使您的 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);

现场演示在这里。

最新更新