如何使用Java8按谓词对列表进行分区?

32

我有一个名为 a 的列表,我想把它分成几个小列表。

比如所有包含“aaa”的项,所有包含“bbb”的项和一些其他谓词。

如何使用Java8实现呢?

我看到了这篇文章,但它只分割成两个列表。

public void partition_list_java8() {

    Predicate<String> startWithS = p -> p.toLowerCase().startsWith("s");

    Map<Boolean, List<String>> decisionsByS = playerDecisions.stream()
            .collect(Collectors.partitioningBy(startWithS));

    logger.info(decisionsByS);

    assertTrue(decisionsByS.get(Boolean.TRUE).size() == 3);
}

我看到了这个帖子,但它非常古老,是在Java 8之前。


3
谓词是布尔类型,只有“true”和“false”两个值。我认为在你的情况下使用“Function”和“Collectors::groupingBy”会更好。 - RealSkeptic
2个回答

41

就像在@RealSkeptic评论中所解释的那样,Predicate只能返回两个结果:true和false。这意味着您只能将数据分成两组。
您需要的是某种Function,它将允许您确定应该分组在一起的元素的某些共同结果。在您的情况下,这样的结果可以是其小写字母中的第一个字符(假设所有字符串都不为空-至少有一个字符)。

现在,使用Collectors.groupingBy(function),您可以将所有元素分组到单独的列表中,并将它们存储在Map中,其中键将是用于分组的公共结果(例如第一个字符)。

因此,您的代码可能如下所示:

Function<String, Character> firstChar =  s -> Character.toLowerCase(s.charAt(0));

List<String> a = Arrays.asList("foo", "Abc", "bar", "baz", "aBc");
Map<Character, List<String>> collect = a.stream()
        .collect(Collectors.groupingBy(firstChar));

System.out.println(collect);

输出:

{a=[Abc, aBc], b=[bar, baz], f=[foo]}

7
您可以使用Collectors.groupingBy将流(分组)->(该分组中的事物列表)转换为映射。如果您不关心分组本身,则调用该映射上的values()方法,以获取您分区的Collection<List<String>>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接