使用JavaStreams过滤复杂列表元素-代码优化
我有一个复杂的元素列表。每个内部列表包含3个字段:代码、名称、版本。 我需要得到列表的最终列表,其中有每个代码的最大版本号 下面的代码片段按预期工作,但正在寻找有效的解决方案使用JavaStreams过滤复杂列表元素-代码优化,java,optimization,java-8,java-stream,Java,Optimization,Java 8,Java Stream,我有一个复杂的元素列表。每个内部列表包含3个字段:代码、名称、版本。 我需要得到列表的最终列表,其中有每个代码的最大版本号 下面的代码片段按预期工作,但正在寻找有效的解决方案 List<List<Object>> lists = new ArrayList<>(); List<List<Object>> finalList = new ArrayList<>(); // each list contains => c
List<List<Object>> lists = new ArrayList<>();
List<List<Object>> finalList = new ArrayList<>();
// each list contains => code, name, version
lists.add(Arrays.asList("code1", "Name1", 1));
lists.add(Arrays.asList("code1", "Name1", 2));
lists.add(Arrays.asList("code1", "Name1", 3));
lists.add(Arrays.asList("code1", "Name1", 3));
lists.add(Arrays.asList("code2", "Name2", 1));
lists.add(Arrays.asList("code2", "Name2", 2));
// get all uniqueCodes
List<Object> uniqueCodes = lists.stream().map(row -> row.get(0)).distinct().collect(Collectors.toList());
// iterate over uniqueCodes
uniqueCodes.stream().forEach(code -> {
// get lists for this uniqueCode
Supplier<Stream<List<Object>>> sameCodeLists = () -> lists.stream().filter(row -> row.get(0) == code);
// get max version of this uniqueCode
int maxVersion = sameCodeLists.get().mapToInt(row -> (int) row.get(2)).max().getAsInt();
// for this uniqueCode, get all Lists containing Max Version
finalList.addAll(sameCodeLists.get().filter(row -> (int) row.get(2) == maxVersion && row.get(0) == code).collect(Collectors.toList()));
});
System.out.println(finalList);
这是适当的,正如预期的那样。寻找代码优化,以较少的迭代完成任务。通过
- 创建一个类并使用它的实例而不是
s李>List
- 使用
和采集器。分组方式
采集器。maxBy
更新 这不是一个简单的任务,所以流API可能不适合。尽管如此,我还是想出了下面的方法,似乎可以做到这一点
List<Entity> result = entities.stream()
// group by code and sort the resulting lists by version
.collect(groupingBy(Entity::getCode, HashMap::new,
collectingAndThen(toList(), e -> e.stream().sorted(comparingInt(Entity::getVersion).reversed()).collect(toList()))))
.values()
.stream()
// keep only the max values
.map(l -> l.size() > 0 ? l.stream().filter(i -> i.getVersion() == l.get(0).getVersion()).collect(toList()) : l)
.flatMap(List::stream)
.collect(toList());
System.out.println(result);
// [
// Entity(code=code2, name=Name2, version=2),
// Entity(code=code1, name=Name1, version=3),
// Entity(code=code1, name=Name1, version=3)
// ]
List result=entities.stream()
//按代码分组并按版本对结果列表排序
.collect(groupingBy)(实体::getCode,HashMap::new,
收集然后(toList(),e->e.stream().sorted(comparingInt(Entity::getVersion).reversed()).collect(toList()))
.values()
.stream()
//只保留最大值
.map(l->l.size()>0?l.stream().filter(i->i.getVersion()==l.get(0.getVersion()).collect(toList()):l)
.flatMap(列表::流)
.collect(toList());
系统输出打印项次(结果);
// [
//实体(代码=代码2,名称=名称2,版本=2),
//实体(代码=代码1,名称=名称1,版本=3),
//实体(代码=代码1,名称=名称1,版本=3)
// ]
您可以通过
- 创建一个类并使用它的实例而不是
s李>List
- 使用
和采集器。分组方式
采集器。maxBy
更新 这不是一个简单的任务,所以流API可能不适合。尽管如此,我还是想出了下面的方法,似乎可以做到这一点
List<Entity> result = entities.stream()
// group by code and sort the resulting lists by version
.collect(groupingBy(Entity::getCode, HashMap::new,
collectingAndThen(toList(), e -> e.stream().sorted(comparingInt(Entity::getVersion).reversed()).collect(toList()))))
.values()
.stream()
// keep only the max values
.map(l -> l.size() > 0 ? l.stream().filter(i -> i.getVersion() == l.get(0).getVersion()).collect(toList()) : l)
.flatMap(List::stream)
.collect(toList());
System.out.println(result);
// [
// Entity(code=code2, name=Name2, version=2),
// Entity(code=code1, name=Name1, version=3),
// Entity(code=code1, name=Name1, version=3)
// ]
List result=entities.stream()
//按代码分组并按版本对结果列表排序
.collect(groupingBy)(实体::getCode,HashMap::new,
收集然后(toList(),e->e.stream().sorted(comparingInt(Entity::getVersion).reversed()).collect(toList()))
.values()
.stream()
//只保留最大值
.map(l->l.size()>0?l.stream().filter(i->i.getVersion()==l.get(0.getVersion()).collect(toList()):l)
.flatMap(列表::流)
.collect(toList());
系统输出打印项次(结果);
// [
//实体(代码=代码2,名称=名称2,版本=2),
//实体(代码=代码1,名称=名称1,版本=3),
//实体(代码=代码1,名称=名称1,版本=3)
// ]
更好的设计是创建一个包含代码、名称、版本的类,然后您可以只使用List
而不是List
。它将使您的代码更干净、更可读、更易于维护。更好的设计是创建一个包含代码、名称、版本的类,这样您就可以使用List
而不是List
。它将使您的代码更干净、更可读和可维护。我在IDE上做了类似的事情,但得出的结论是使用toMap
,我建议这种方法避免将可选的作为映射值,即entities.stream().collect(toMap(Entity::getCode、Function.identity()、BinaryOperator.maxBy(Comparator.comparingInt(Entity::getVersion)))
或者您可以继续使用当前的方法,但使用收集,然后使用
和finisher函数来获取地图
。另外,另一个注意事项是,赞成比较
而不是比较
@Aomine谢谢。是的,我正在考虑一个finisher,这就是我想要的。@Aomine当然,它应该是 比较IT
@andreTobilko/@Aomine-如果您观察问题中的输出,则需要收集具有最大版本的所有列表元素。在您的答案中,实体条目:[“code1”,“Name1”,3]是两次。由于允许重复条目,所以输出也应该包含两个条目。最终输出应该是一个列表,我们可以尝试不使用Map吗?我在IDE上做了类似的事情,但得出的结论是使用toMap
,我建议使用这种方法来避免将可选的作为Map值,即entities.stream().collect(toMap(Entity::getCode,Function.identity(),BinaryOperator.maxBy(Comparator.comparingit(Entity::getVersion)))
或者您可以继续使用当前的方法,但使用收集,然后使用
和finisher函数来获取地图
。另外,另一个注意事项是,赞成比较
而不是比较
@Aomine谢谢。是的,我正在考虑一个finisher,这就是我想要的。@Aomine当然,它应该是 比较IT
@andreTobilko/@Aomine-如果您观察问题中的输出,则需要收集具有最大版本的所有列表元素。在您的回答中,实体条目:[“code1”,“Name1”,3]是两倍。由于允许重复条目,因此输出还应包含两个条目。最终输出应为列表,我们可以尝试不使用映射吗?
Map<String, Optional<Integer>> result = entities.stream()
.collect(groupingBy(Entity::getCode,
collectingAndThen(maxBy(Comparator.comparingInt(Entity::getVersion)),
opEntity -> opEntity.map(Entity::getVersion))));
System.out.println(result);
// {code2=Optional[2], code1=Optional[3]}
List<Entity> result = entities.stream()
// group by code and sort the resulting lists by version
.collect(groupingBy(Entity::getCode, HashMap::new,
collectingAndThen(toList(), e -> e.stream().sorted(comparingInt(Entity::getVersion).reversed()).collect(toList()))))
.values()
.stream()
// keep only the max values
.map(l -> l.size() > 0 ? l.stream().filter(i -> i.getVersion() == l.get(0).getVersion()).collect(toList()) : l)
.flatMap(List::stream)
.collect(toList());
System.out.println(result);
// [
// Entity(code=code2, name=Name2, version=2),
// Entity(code=code1, name=Name1, version=3),
// Entity(code=code1, name=Name1, version=3)
// ]