【问题标题】:Using stream to check if list has only specific elements permutations in Java使用流检查列表是否只有Java中的特定元素排列
【发布时间】:2019-01-02 22:54:48
【问题描述】:

我正在尝试使用流来解决此问题,如果有人遇到此问题但找不到此问题,我会查找它。 所以我有一个包含三个元素的列表,我们称之为 list1,另一个列表说 list2,它可以有不同的元素,也可以包含 list1 中的重复项。

我想要达到的目标:-

  1. 检查 list2 是否有任何不在 list1 中的元素。
  2. 检查 list2 一次是否只有 list1 中的 2 项。

对于 2 - 我可以使用 set,将 list2 转换为 set 并查看 list1 是否包含所有集合。

但我想知道我是否可以在这里使用流!

例如

list1 (1,2,3) 和 list2 (1,1,2,2) - 返回 true

list1 (1,2,3) 和 list2 (1,1,3,3) - 返回 true

list1 (1,2,3) 和 list2 (1,1,2,2,4) -return false

我希望这能说明问题

【问题讨论】:

    标签: java java-stream


    【解决方案1】:
      public static <T> boolean func(List<T> list1, List<T> list2) {
        return list2.stream()
            .distinct()
            .map(list1::contains)
            .reduce(0,
                (result, current) -> result < 0 ? -1 : (current ? result + 1 : -1),
                (a, b) -> a < 0 || b < 0 ? -1 : a + b) == 2;
      }
    

    但建议你不要将流用于如此复杂的逻辑。

    【讨论】:

    • 哈哈,是的,看起来很吓人!
    • 可以通过将累加器更改为result &lt; 0 || !current ? -1 : result + 1来稍微简化。但它看起来仍然很吓人,需要一些时间才能理解:D
    • @MalteHartwig 当更短意味着更简单时,我们可以在合并函数中使用(a|b) &lt; 0 而不是a&lt;0 || b&lt;0……甚至(a,b) -&gt; ((a|b)&gt;&gt;31)|(a+b)
    • @Holger 更短,是的,但要理解这一点......它需要一些广泛的代码 cmets IMO :) 仍然很棒,虽然
    • @Holger 不是更短,我试图扁平化嵌套条件。嵌套是不必要的,因为三个结果中的两个是相同的。那些位运算符看起来很有趣,但我个人尽量避免使用它们,因为不是每个人(包括我)都能直观地理解它们。
    【解决方案2】:

    流可能不是解决此问题的最有效方法。尽管如此,当我们发现list1 中包含第三个元素或未包含第一个元素时,这是另一种具有短路 优势的方法:

    public static <T> boolean func(List<T> list1, List<T> list2)
    {
        AtomicLong count = new AtomicLong(0);
        return list2.stream()
                    .distinct()
                    .allMatch(element -> list1.contains(element) &&
                                         count.incrementAndGet() < 3)
               && count.get() == 2;
    }
    

    不过,我们必须“作弊”一点:为了不通过完整的流,我们必须借助计数器来限制元素。

    检查&amp;&amp; count.get() == 2 确保您恰好有两个元素包含在list1 中。如果 0 或 1 个元素也可以接受,请删除该检查。

    【讨论】:

    • 这很好,简洁:-)
    【解决方案3】:

    怎么样:

    return Optional.of(list2)
            .filter(list -> list.stream().allMatch(list1::contains))
            .map(list -> list.stream().distinct().map(list1::contains))
            .map(stream -> stream.mapToInt(x -> x ? 1 : 0))
            .map(IntStream::sum)
            .filter(sum -> sum == 2)
            .isPresent();
    

    不幸的是,您实际上执行了两次相同的流操作。或者,为避免这种情况,请收集流并重新转换它:

    List<Boolean> containedInFirst = list2.stream()
            .distinct()
            .map(list1::contains)
            .collect(Collectors.toList());
    return Optional.of(containedInFirst)
            .filter(list -> list.stream().allMatch(x -> x))
            .map(list -> list.stream().mapToInt(x -> x ? 1 :0))
            .map(IntStream::sum)
            .map(sum -> sum == 2)
            .filter(sum -> sum == 2)
            .isPresent();
    

    您实际上是在创建两个可选曲目:一个符合您的要求,一个不符合您的要求。任何时候你发现一些不匹配的东西,你都会用过滤器把它扔掉。 isPresent 仍在准备中的任何内容都符合您的条件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-06
      • 1970-01-01
      • 1970-01-01
      • 2021-09-25
      • 1970-01-01
      • 1970-01-01
      • 2012-03-15
      • 2021-03-13
      相关资源
      最近更新 更多