如何使用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]
答案 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)
如果您只想计数一个或零,则对于找到第一个匹配项或找不到匹配项,请从第一个{{ 3}},stream和list来测试第二个filter是否流传输了第一个列表中的所有项,predicate是否匹配,并通过list contains返回数字1
或0
。
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 empty和ask 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)
假设您要将结果保存在matchList
和count
中,则可以使用流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())
);