如何判断列表是否是java8流的另一个子序列?

Run*_*Run 8 java functional-programming java-8 java-stream

例如,我有一个很长的列表[1, 2, 3, ..., 10],一个很短的列表,[1, 3, 6]然后我可以告诉我,短的列表是另一个的子序列.另一方面,列表[1 6 3]不是因为它违反了订单约束.

下面是我这个问题的java7样式代码:

List<Integer> sequence = Arrays.asList(1, 3, 6);
List<Integer> global = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Iterator<Integer> iterGlobal = global.iterator();
boolean allMatch = true;
for(Integer itemSequence: sequence) {
    boolean match = false;
    while(iterGlobal.hasNext()) {
        if(itemSequence.equals(iterGlobal.next())) {
            match = true;
            break;
        }
    }
    if(!match) {
        allMatch = false;
        break;
    }
}
System.out.println(allMatch); //=> true
Run Code Online (Sandbox Code Playgroud)

而我的愿望是找到一个java8流样式来实现相同的结果.

Hol*_*ger 6

真正的功能性解决方案,即不包含可变状态,很难找到.迄今为止所有答案都包含可变状态这一事实最能说明这一点.

此外,没有List.indexOf(T object, int startIndex)操作.为了说明它是多么有用,让我们通过辅助方法来定义它:

public static int indexOf(List<?> list, int startIndex, Object o) {
    if(startIndex!=0) list=list.subList(startIndex, list.size());
    int ix=list.indexOf(o);
    return ix<0? -1: ix+startIndex;
}
Run Code Online (Sandbox Code Playgroud)

如果这是一个问题,那么很容易找到没有临时对象的替代实现

现在,使用可变状态的简单解决方案是:

boolean allMatch = sequence.stream().allMatch(new Predicate<Integer>() {
    int index = 0;
    public boolean test(Integer t) {
        return (index = indexOf(global, index, t)) >=0;
    }
});
Run Code Online (Sandbox Code Playgroud)

没有可变状态的功能解决方案需要在两个列表中保持两个位置的值类型.当我们使用int[2]数组时,解决方案是:

boolean allMatch = Stream.iterate(
        new int[]{ 0, global.indexOf(sequence.get(0)) },
        a -> new int[] { a[0]+1, indexOf(global, a[1], sequence.get(a[0]+1)) }
    )
    .limit(sequence.size())
    .allMatch(a -> a[1]>=0);
Run Code Online (Sandbox Code Playgroud)


Run*_*Run 5

我是提问者,我首先回答我的问题只是为了标记:

List<Integer> sequence = Arrays.asList(1, 3, 6);
List<Integer> global = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Iterator<Integer> iter = global.iterator();
boolean subSequence = sequence.stream().allMatch(itemSequence -> {
    return Stream.generate(iter::next)
            .anyMatch(itemGlobal -> itemSequence.equals(itemGlobal));
});
System.out.println(subSequence);
Run Code Online (Sandbox Code Playgroud)

它适用于序列列表 [1, 3, 6],而对于序列 [1, 6, 3] 抛出错误 java.util.NoSuchElementException。这不是我最终想要达到的。

  • 嗯,如果这不是您想要实现的目标,那么您不应该将其发布为答案,因为它会使未来的读者在寻找此问题的实际解决方案时感到困惑。最好将其作为示例包含在您的问题中。 (2认同)