繁体   English   中英

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

[英]How to judge whether a list is a sub sequence of another with java8 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

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

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

此外,没有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;
}

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

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

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

没有可变状态的功能解决方案需要在两个列表中保持两个位置的值类型。 当我们使用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);

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

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);

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

我认为你非常接近解决方案(我甚至没有考虑像这样的Iterator ,所以对你来说是一个加号)。 问题是Stream.generate是一个无限的流。

我已经改变了你的代码。

    Iterator<Integer> iter = global.iterator();

    boolean subSequence = sequence.stream().allMatch(itemSequence -> {
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iter, Spliterator.ORDERED), false)
                .anyMatch(itemGlobal -> itemSequence.equals(itemGlobal));
    });
    System.out.println(subSequence);

@ Eugene的@ Run的答案的变体将涉及在全局List <>值上调用Iterable :: spliterator,然后将结果应用于StreamSupport :: stream:

final Spliterator<Integer> spliterator = global.spliterator();

final boolean subSequence = sequence.stream().allMatch(
  itemSequence -> StreamSupport.stream(
    spliterator,
    false
  ).anyMatch(itemSequence::equals)
);

System.out.println(subSequence);

看到霍尔格回答后,我会再添加一个选项; 但这只适用于jdk-9 Stream.iterate

我以同样的方式定义了一个辅助方法,有点不同:

private static int fits(List<Integer> global, int elementIndex, int element) {
    return global.indexOf(element) >= elementIndex ? global.indexOf(element) : -1;
}

然后只使用int[2]

boolean allMatch = Stream.iterate(new int[] { 0, 0 },
            array -> array[0] < sequence.size() && array[1] >= 0,
            array -> new int[] { array[0] + 1, fits(global, array[1], sequence.get(a[0])) })
            .allMatch(array -> array[0] >= array[1]);

编辑 Holger是对的,这只适用于非重复。

我可以写它也重复,但随后从该点受到fits需要,现两次被调用。

 boolean allMatch = Stream.iterate(new int[] { 0, 0 },
            a -> {
                return a[0] == sequence.size() ? false : fits(global, sequence.get(a[0])) >= a[1];
            },
            a -> {
                int nextFits = fits(global, sequence.get(a[0]));
                return new int[] { a[0] + 1, nextFits > a[1] ? nextFits + 1 : -1 };
            })
            .count() == sequence.size();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM