【问题标题】:Compare two lists of strings using java stream使用 java 流比较两个字符串列表
【发布时间】:2019-12-29 21:46:24
【问题描述】:

如何使用 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]

【问题讨论】:

  • 我不想要包含,因为在以下情况下,包含将匹配“Steve”和“Steve Jobs” - 仅适用于字符串。如果您使用nameList1.contains(someString),它将告诉您数组是否包含确切的字符串。
  • 在这里使用流可以实现什么? String result = null; for (String name1 : nameList1) { if (nameList2.contains(name1)) { result = name1; break; }}.
  • “还有一个条件,问题已更新。请看一下。谢谢。” - 不要那样做。改变问题是在浪费那些试图帮助你的人的时间。
  • 应该做的是: 1) 阅读/注意你收到的cmets。 2) 尝试从您已经给出的答案中找出解决问题的方法。 3)如果你不能解决,问一个新的问题,引用这个问题并添加新的条件。
  • 那么您是在尝试查找第一个匹配的名称,然后停止检查其他名称吗?

标签: java java-stream


【解决方案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 是进程数。这是做出一些假设,并忽略了潜在的内存争用影响。)

【讨论】:

    【解决方案2】:

    tl;博士

    如果您只想计数 1 或 0,对于 找到第一个匹配项未找到匹配项,从第一个 list 创建一个 streamfilterpredicate 测试第二个 list contains 第一个列表中的每个流式传输项目是否找到 limit to the first 匹配,并通过 ternary statement 返回数字 10

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

    并不是我推荐单线。有关更多实用代码,请参见下文。并查看correct Answer by Stephen C 了解此主题的变体。

    详情

    给定两个String 对象列表:

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

    匹配列表

    您可以获得匹配项的List

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

    单场比赛

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

    如果这是您的目标,那么您使用List 作为结果,以及计数器没有意义。结果,您只能拥有一个或零个对象。

    Optional

    所有项目都可能不匹配,因此我们可能无法取回项目。为此目的,发明了Optional 类,以涵盖返回单个对象或不返回对象(null)的情况。 Optional 类可防止 NullPointerException 对 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 对象if it contains 一个String 对象或if it is empty。如果没有,您可以将ask for an alternate value 用作默认值。你could throwNoSuchElementException 如果你希望总会有一个匹配。或者您可以在Optional 为空的情况下执行您自己的逻辑。请参阅课程文档并搜索 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]

    【讨论】:

      【解决方案3】:

      假设您要将结果保存在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
      

      【讨论】:

        猜你喜欢
        • 2019-04-08
        • 2019-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-05
        • 1970-01-01
        相关资源
        最近更新 更多