使用Java流比较两个字符串列表

时间:2019-12-29 21:46:24

标签: java java-stream

如何使用Java Streams进行跟踪?

我在这里尝试比较两个字符串列表。如果有任何元素匹配,则在第一个匹配中增加计数,将匹配的值添加到matchList并中断循环。

List<String> nameList1 = Arrays.asList("Bill", "Steve", "Mark");
List<String> nameList2 = Arrays.asList("Steve Jobs", "Mark", "Bill");

int count = 0;
List<String> matchList = new ArrayList<>();

for (String name1 : nameList1) {
    if (nameList2.contains(name1)) {
            count++;
            matchList.add(name1);
            break;
        }
    }
}

System.out.println(count); // 1
System.out.println(matchList); // [Bill]

4 个答案:

答案 0 :(得分:1)

首先,现有的带有循环的解决方案就可以了。简单地将其转换为使用流的解决方案并没有改善。

这就是我要做的。注意:这未经测试。

// Naive version

List<String> nameList1 = Arrays.asList("Bill", "Steve", "Mark");
List<String> nameList2 = Arrays.asList("Steve Jobs", "Mark", "Bill");

List<String> matchList = nameList1.stream()
    .filter(nameList2::contains)
    .limit(1)
    .collect(Collectors.toList());

count = matchList.size();

请注意,无需追加到列表并增加计数。

如果您打算尝试并行化它,那么流可以提供帮助,但是您需要以不同的方式进行操作。

最后,如果您真的非常在意性能,并且nameList2.size() == N足够大,则将nameList2转换为HashSet会更快。这将其从O(MN)算法转变为O(M)算法。

(相比之下,并行化朴素版本只会给您O(MN/P)最好的复杂度 ,其中P是进程数。这是在做一些假设,并且忽略了潜在的内存争用效果)

答案 1 :(得分:0)

tl; dr

如果您只想计数一个或零,则对于找到第一个匹配项找不到匹配项,请从第一个{{ 3}},streamlist来测试第二个filter是否流传输了第一个列表中的所有项,predicate是否匹配,并通过list contains返回数字10

int count = 
        List.of( "Bill" , "Steve" , "Mark" )
        .stream()
        .filter( ( String s ) -> List.of( "Steve Jobs" , "Mark" , "Bill" ).contains( s ) )
        .findFirst()
        .isPresent() 
        ? 1 : 0 
;

不是,我建议那种单线。请参阅下面的更多实用代码。并参见limit to the first,了解有关此主题的各种变化。

详细信息

给出两个String对象的列表:

List < String > these = List.of( "Bill" , "Steve" , "Mark" );
List < String > those = List.of( "Steve Jobs" , "Mark" , "Bill" );

比赛列表

您可以获得ternary statement个匹配的项目。

List < String > matches = these.stream().filter( s -> those.contains( s ) ).collect( Collectors.toList() );

单场比赛

但是您显然只要求提供恰好匹配的第一项。

如果这是您的目标,则对结果使用List,而计数器则没有意义。结果只能有一个或零个对象。

Optional

所有项目均不匹配,因此我们可能不会退回任何项目。为此,发明了correct Answer by Stephen C类,以涵盖返回单个对象或不返回任何对象(空)的情况。 Optional类可防止List避免对返回值NULL的混合处理。

Optional < String > match =                   // `Optional` is a class wrapping another object, the payload, which may be NULL. 
    these
    .stream()                                 // Produce a stream of items from this `List`.
    .filter(                                  // Apply a predicate test against each item produced in the stream. Items that pass the test are fed into a new second stream.
        ( String s ) -> those.contains( s )   // Predicate.
    )                                         // Returns another `Stream`.
    .findFirst()                              // Halts the new (second) stream after producing the first item. Returns an `Optional` object, a wrapper around the payload which may be NULL.
;

您可以要求Optional对象NullPointerException一个String对象或Optional。如果没有,您可以if it contains用作默认值。如果您希望始终有一个匹配项,则您if it is emptyask for an alternate value。或者,您可以在Optional为空的情况下执行自己的逻辑。请参阅类doc,并搜索Stack Overflow以了解有关Optional的更多信息。

if( match.isPresent() ) {
    System.out.println( "Match found: " + match.get() ) ;
}

转储到控制台。

System.out.println( "these = " + these );
System.out.println( "those = " + those );
System.out.println( "matches = " + matches );
System.out.println( "match = " + match );
  

这些= [比尔,史蒂夫,马克]

     

那些= [史蒂夫·乔布斯,马克,比尔]

     

匹配= [比尔,马克]

     

match =可选[Bill]

答案 2 :(得分:0)

假设您要将结果保存在matchListcount中,则可以使用流peek方法保存中间结果

List<String> nameList1 = Arrays.asList("Bill", "Steve", "Mark");
        List<String> nameList2 = Arrays.asList("Steve Jobs", "Mark", "Bill");

        final int[] count = {0};
        List<String> matchList = new ArrayList<>();

        nameList1.stream().filter(nameList2::contains)
                .peek(s -> {
                    matchList.add(s);
                    count[0]++;
                })
                .findFirst();

        matchList.forEach(System.out::println); //Bill
        System.out.println(count[0]); //1

答案 3 :(得分:-1)

您可以像这样从sec列表包含它们的第一个列表中过滤所有字符串

List<String> nameList1 = Arrays.asList("Bill", "Steve", "Mark");
List<String> nameList2 = Arrays.asList("Steve Jobs", "Mark", "Bill");
matchList.addAll(
    nameList1.stream().filter(name1->{
        return nameList2.stream().filter(name2->{
            return name2.equals(name1);
        }).collect(Collectors.toList()).size()>0;
    }).collect(Collectors.toList())
);