使用Java的lambda和streams将文本文件映射到映射

使用Java的lambda和streams将文本文件映射到映射,java,collectors,Java,Collectors,所以我的文本文件包含5个字段,我想创建一个地图 从中可以看出,Pair是Apache的ImmutablePairhaving实例,将5个字段中的2个字段作为键,该映射的值将是一个列表,其中键的每个列表将包含其余3个字段,因此如果该文件如下所示: A,B,1,2,3 A,C,4,5,9 A,B,3,4,5 A,C,5,6,7 K:(A,B) V:((1,2,3),(3,4,5)) K:(A,C) V:((4,5,9),(5,6,7)) 结果图如下所示: A,B,1,2,3 A,C,4,5,

所以我的文本文件包含5个字段,我想创建一个地图 从中可以看出,Pair是Apache的ImmutablePairhaving实例,将5个字段中的2个字段作为键,该映射的值将是一个列表,其中键的每个列表将包含其余3个字段,因此如果该文件如下所示:

A,B,1,2,3
A,C,4,5,9
A,B,3,4,5
A,C,5,6,7
K:(A,B)
 V:((1,2,3),(3,4,5))
K:(A,C)
 V:((4,5,9),(5,6,7))
结果图如下所示:

A,B,1,2,3
A,C,4,5,9
A,B,3,4,5
A,C,5,6,7
K:(A,B)
 V:((1,2,3),(3,4,5))
K:(A,C)
 V:((4,5,9),(5,6,7))
我试图通过尽可能多地使用lambda和streams来实现这一点,这是我的临时代码,它可以工作,但它返回整行的值:

  private Map<Pair<String, String>, List<List<String>>> createMultimapFromFile() {
    Map<Pair<String, String>, List<List<String>>> map = new BufferedReader(
        new InputStreamReader(getClass().getResourceAsStream(MAPING_FILENAME)))
        .lines()
        .map(line -> Arrays.asList(line.split(COMMA)))
        .filter(lineAsList -> lineAsList.size() == REQUIRED_FILE_LINE_LENGTH)
        .collect(Collectors.groupingBy(filteredLine ->
            ImmutablePair.of(filteredLine.get(1), filteredLine.get(2))));
    return map;
  }
此对Collectors.groupingBy的调用使用了实现,默认情况下将映射值返回为List,但我希望返回一个子列表,但我找不到该子列表,以节省内存空间。 我觉得这是正确的方法,正如描述中所说……然后使用指定的下游收集器对与给定键相关联的值执行缩减操作。 只是找不到一个预先制作的收集器,我可以指定代码来完成列表。 有人有什么建议吗?

CollectorMapping会帮你做的

try(BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(MAPING_FILENAME), "utf-8"))) {
  return reader.lines()
    .map(line -> line.split(","))
    .filter(lineAsList -> lineAsList.length == REQUIRED_FILE_LINE_LENGTH)
    .map(data -> Pair.of(ImmutablePair.of(data[0], data[1]), Arrays.asList(data[2], data[3], data[4])))
    .collect(Collectors.groupingBy(p -> p.getLeft(), Collectors.mapping(p -> p.getRight(), Collectors.toList())));
} catch (Exception e) {}
而输出是这样的

{(A,C)=[[4, 5, 9], [5, 6, 7]], (A,B)=[[1, 2, 3], [3, 4, 5]]}
Pair是ApacheCommonsLang库中的元组。使用此处仅用于保存值。您可以使用任何其他对象来实现此目的

或者,也可以这样写

.map(data -> Pair.of(ImmutablePair.of(data[0], data[1]), Arrays.asList(data[2], data[3], data[4])))
.collect(Collectors.groupingBy(p -> p.getLeft(), Collectors.mapping(p -> p.getRight(), Collectors.toList())));

//without pair
.collect(Collectors.groupingBy(data -> ImmutablePair.of(data[0], data[1]), Collectors.mapping(data -> Arrays.asList(data[2], data[3], data[4]), Collectors.toList())));

考虑做一个类来代表你的记录,也许是密钥而不是对。这不仅会增加解析代码的可读性,还会增加使用解析数据的所有代码的可读性。Java是一种强类型语言。试图摸索迷宫般的地图、列表和装箱类型对读者来说是令人厌烦的。还要注意的是,您的示例或此处的其他答案都不能关闭流。这是非常糟糕的。关闭该流可能比解决最初的问题更重要。非常感谢。不需要.mapdata->Pair.of…,…步骤。这对调用的两个参数正是您可以在随后的collect操作中直接使用的参数,而不是getLeft和getRight。您应该为InputStreamReader指定一个编码,因为嵌入式资源肯定有一个固定的编码,当软件在不同的目标系统上运行时,该编码不会改变。