关闭。这个问题需要更多focused .它目前不接受答案。
想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post .
去年关闭。
Improve this question
我有一个对象列表。我想做一个 groupBy 以便有:
和一个不是上述任何一个的组。
我可以:
for (Object obj: myList) {
if (obj instanceof Long) || (obj instanceof String) {
// add to sublist1
} else if (obj instanceof Map) {
// sublist2
} else {
// sublist3
}
}
我如何使用 Java 8?
最佳答案
当我遇到这样的问题时,我通常会“由内而外”处理它,也就是说,我会想到一些看起来可能有用的逻辑小块。然后,我通过组合来解决完整的问题。
例如,您需要一种方法来根据对象是否是一组类中的一个类的实例来区分对象。 (对于 Integer、Long、String 和 Boolean 的集合,我假设您指的是类似原始类的类,而不是数字。)这向我建议了一个函数,它接受一个对象和一组这样的类,并确定该对象是否是其中任何一个的实例。这就是它的样子:
boolean instanceOfAny(Object obj, Set<Class<?>> set) {
return set.stream().anyMatch(clazz -> clazz.isInstance(obj));
}
并非巧合,此函数的形状类似于
Predicate<Object>
。你可以这样称呼它:if (instanceOfAny(obj, Set.of(Integer.class, Long.class)) { ...
问题是,我们有几个这样的谓词,我们将要根据谓词匹配的内容对事物进行分组。这建议了一个谓词列表。您希望一组中的类原始类和第二组中的 Maps。该列表将如下所示:
List<Predicate<Object>> predicates = List.of(
obj -> instanceOfAny(obj, Set.of(Integer.class, Long.class, String.class, Boolean.class)),
obj -> instanceOfAny(obj, Set.of(Map.class)));
有一个关于如何处理“其他”案例的问题。您可以在末尾放置一个谓词
obj -> true
,这将保证匹配。但是匹配这些谓词的代码仍然会出现没有谓词匹配的情况。你可以在那里抛出一个断言错误,或者只是在代码中加入,如果没有谓词匹配,项目就会被放到另一个组中。由于我们有一个谓词列表,将它们分组的自然值是列表中谓词的索引。我们可以随意为“不匹配”组分配一个值。由于它在问题陈述的最后列出,我将分配一个超出列表中最后一个索引的“不匹配”索引。
给定一个对象,我们可以在列表上编写一个循环并依次调用该对象上的每个谓词。但是我们想使用流和 lambdas,所以让我们这样做。 (我实际上认为无论如何使用流效果都很好。)这是使用旧的 IntStream-over-list-indices 技巧来做到这一点的方法:
int grouper(Object obj) {
return IntStream.range(0, predicates.size())
.filter(i -> predicates.get(i).test(obj))
.findFirst()
.orElse(predicates.size());
}
在这里,我们对列表索引进行流式处理,并从
filter
操作中调用每个谓词。这为我们提供了匹配谓词的索引。我们只想要第一个,所以我们使用 findFirst
。这给了我们一个 OptionalInt
,如果没有任何谓词匹配,则它为空,因此我们在这种情况下替换列表大小。现在,让我们对它进行一些输入:
List<Object> input = List.of(
true, 1, 2L, "asdf", Map.of("a", "b"), new BigInteger("23456"),
Map.of(3, 4), List.of("x", "y", "z"), false, 17, 'q');
为了处理输入,我们使用这个短流:
Map<Integer, List<Object>> result = input.stream().collect(groupingBy(this::grouper));
result.forEach((k, v) -> System.out.println(k + " => " + v));
输出是:
0 => [true, 1, 2, asdf, false, 17]
1 => [{a=b}, {3=4}]
2 => [23456, [x, y, z], q]
综合起来,我们有以下几点:
boolean instanceOfAny(Object obj, Set<Class<?>> set) {
return set.stream().anyMatch(clazz -> clazz.isInstance(obj));
}
List<Predicate<Object>> predicates = List.of(
obj -> instanceOfAny(obj, Set.of(Integer.class, Long.class, String.class, Boolean.class)),
obj -> instanceOfAny(obj, Set.of(Map.class)));
int grouper(Object obj) {
return IntStream.range(0, predicates.size())
.filter(i -> predicates.get(i).test(obj))
.findFirst()
.orElse(predicates.size());
}
void main() {
List<Object> input = List.of(
true, 1, 2L, "asdf", Map.of("a", "b"), new BigInteger("23456"),
Map.of(3, 4), List.of("x", "y", "z"), false, 17, 'q');
Map<Integer, List<Object>> result =
input.stream().collect(groupingBy(this::grouper));
result.forEach((k, v) -> System.out.println(k + " => " + v));
}
关于java - 将列表拆分为 3 个子列表 Java 8+,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60676088/