同时遍历 2 个列表

问题描述

我正在尝试将以下代码转换为 Java 8(使用流),但不确定如何使用流将 2 个列表一起迭代。

public class ComparisonString {
    private static List<String> input;

    public static void main(String[] args) {
        input = Arrays.asList("TRUE","FALSE","TRUE","N/A");
        ComparisonString cs = new ComparisonString();
        System.out.println(cs.getMatchedOutput(Arrays.asList("TRUE","N/A","FALSE")));

    }
    /**
     * Check whether the 'input' List and the 'givenInput' List match.
     * If a value is "N/A" in either lists then it means does-not-matter/don't-check-for-a-match-and-go-next
     * @param givenInput
     * @return
     */
    public Optional<String> getMatchedOutput(final List<String> givenInput) {
        boolean flag = true;
        for (int i = 0; i < givenInput.size(); i++) {
            if (this.input.get(i) != null
                    && !(this.input.get(i).equalsIgnoreCase("N/A")
                    || givenInput.get(i).equalsIgnoreCase("N/A"))
                    && !this.input.get(i).equalsIgnoreCase(givenInput.get(i))) {
                flag = false;
                break;
            }
        }
        if (flag) {
            return Optional.of("flag = true");
        } else {
            return Optional.empty();
        }
    }
}

解决方法

可以使用 IntStream 为两个列表生成索引流,然后过滤掉不相关的列表值并匹配剩余的值:

public Optional<String> getMatchedOutput(final List<String> givenInput) {
    return IntStream.range(0,givenInput.size())
             .filter(i -> null != input.get(i) && null != givenInput.get(i))
             .filter(i -> !"N/A".equalsIgnoreCase(input.get(i)) && !"N/A".equalsIgnoreCase(givenInput.get(i)))
             .allMatch(i -> input.get(i).equalsIgnoreCase(givenInput.get(i)))
        ? Optional.of("flag = true")
        : Optional.empty();
}

测试已知数据:

input = Arrays.asList("TRUE","FALSE","TRUE","N/A");
ComparisonString cs = new ComparisonString();
 System.out.println(cs.getMatchedOutput(Arrays.asList("TRUE","N/A","FALSE")));

印刷品:

Optional[flag = true]
,

您这样做的方式没有任何问题,而流对于此来说太过分了,而且效率可能较低。但是,我会提出两个建议:

  • 不需要布尔值。比较失败后立即return Optional.empty()。否则,return Optional.of("flag = true") 在 for 循环之后。
  • 您应该检查不相等的 List 大小。如果您为循环选择较长的循环,则可能会引发异常。您可以采用两种大小中的 Math.min,忽略比较中的额外元素,或者只检查列表大小是否相等,然后根据应用程序的列表相等性决定这意味着什么。
,

不幸的是,您不能使用流同时操作 2 个列表。您可以做的是使用迭代器。我试着写了一些代码,它应该是这样的:

public static void streamTest(List<String> givenList) {
    List<String> testing = new ArrayList<>();
    IntStream.range(0,givenList.size())
            .parallel()
            .forEach(i -> {
                if (input.get(i) != null
                        && !(input.get(i).equalsIgnoreCase("N/A")
                        || givenList.get(i).equalsIgnoreCase("N/A"))
                        && !input.get(i).equalsIgnoreCase(givenList.get(i)))
                    testing.add("false");
            });
    if (testing.isEmpty())
        System.out.println("flag = true");
    else
        System.out.println("flag = false");
}

我希望这对您有所帮助,并让您有一个开始。

,

您可以使用另一种可能的解决方案。它看起来像 python zip 函数。

public class ComparisonString {
    private static List<String> input;

    public static void main(String[] args) {
        input = Arrays.asList("TRUE","N/A");
        ComparisonString cs = new ComparisonString();
        System.out.println(cs.getMatchedOutput(
                Arrays.asList("TRUE","FALSE")));
    }

    public Optional<String> getMatchedOutput(final List<String> givenInput) {
        boolean notFlag = IntStream.range(0,input.size())
                // zip to new object
                .mapToObj(i -> new Pair<>(input.get(i),givenInput.get(i)))

                // stop when the false flag is found
                .anyMatch(p -> {
                    String inputValue = p.getKey();
                    String givenValue = p.getValue();

                    // true breaks the stream
                    return inputValue != null
                            && !("N/A".equalsIgnoreCase(inputValue)
                            || "N/A".equalsIgnoreCase(givenValue))
                            && !inputValue.equalsIgnoreCase(givenValue);
                });
        if (!notFlag) {
            return Optional.of("flag = true");
        } else {
            return Optional.empty();
        }
    }
}

输出

Optional[flag = true]
,

您可以使用 IntStream#noneMatch 方法简化代码,如下所示:

private static List<String> input;

public static void main(String[] args) {
    input = Arrays.asList("TRUE","N/A");
    System.out.println(
            getMatchedOutput(Arrays.asList("TRUE","FALSE")));
}

public static Optional<String> getMatchedOutput(final List<String> givenInput) {
    return IntStream.range(0,givenInput.size()).noneMatch(i ->
            input.get(i) != null
                    && !(input.get(i).equalsIgnoreCase("N/A")
                    || givenInput.get(i).equalsIgnoreCase("N/A"))
                    && !input.get(i).equalsIgnoreCase(givenInput.get(i)))
            ? Optional.of("flag = true") : Optional.empty();
}

另见:Filter HashMap based on multiple 'optional' conditions