2017-02-17 22 views
8

例如,我有一個長列表[1, 2, 3, ..., 10],和一個簡短的[1, 3, 6],那麼我可以說短一個是另一個的子序列。另一方面,清單[1 6 3]不是因爲它違背了訂單限制。如何判斷一個列表是否是另一個具有java8流的子序列?

下面是對這個問題我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流風格,以達到同樣的效果。

+1

如果輸入是'1,2,3,4,5,6,3',那麼'1,3,6'和'1,6,3'可能是有效的? – Flown

+0

我想答案是肯定的。 – bartektartanus

+0

@Fown:是的,兩者都有效。 – Run

回答

4

我提問,我先回答我的問題只是標記:

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。這不是我最終想要達到的。

+1

嗯,如果這不是你想達到的目的,那麼你不應該把它作爲答案發布,因爲它可能會混淆未來的讀者尋找這個問題的實際解決方案。在你的問題中包括它作爲一個例子會更好。 – walen

+0

@瓦倫:是的,謝謝你的建議。 – Run

2

我認爲你真的接近解決方案(我甚至沒有考慮像這樣的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); 
+0

看起來不錯,主意不錯。 – Run

2

的@潤的回答會涉及調用可迭代::對全球列表<>值spliterator @尤金的變型的一種變體,然後應用結果StreamSupport ::流:

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

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

System.out.println(subSequence); 
+0

您是否嘗試過輸入'1,6,3'的解決方案? – Eugene

+0

如果global = [1,6,3],subSequence = false,並且global = [1,3,6],那麼subSequence爲true,遵循@ Run的順序約束。請注意,List :: spliterator報告Spliterator.SIZED和Spliterator.ORDERED,就像在實際的List接口默認方法中一樣。 – srborlongan

+1

我不好,謝謝。 – Eugene

6

房地產功能性解決方案,即不納入可變狀態,很難找到。迄今爲止所有答案都包含可變狀態,這一點可以很好地說明問題。

此外,沒有List.indexOf(T object, int startIndex)操作。爲了說明這一點,那將是多麼有用的是,我們通過helper方法把它定義:

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

這很好。我希望你不介意我把你的想法和使用它有點不同,因爲jdk-9有可能迭代一個Stream,就像使用'hasNext'和'next'的Iterator一樣。 – Eugene

0

我會看到霍爾格回答後添加另一種選擇;但這隻適用於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]); 

編輯 霍爾格是正確的,這將只適用於非重複。

我也可以把它寫成重複的,但是現在有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(); 
+0

你的'fits'方法的問題是,當列表有重複時,它不會產生相同的結果。除此之外,每次從頭開始搜索,甚至兩次都可能比創建輕量級子列表實例的成本高得多。 – Holger

+0

@Holger的確你是對的。 thx爲這個輸入! – Eugene

+0

請注意'表達? false:condition'與'!expression && condition'相同。換句話說,而不是'a [0] == sequence.size()? false:fits(global,sequence.get(a [0]))> = a [1]',您可以編寫'a [0]!= sequence.size()&& fits(global,sequence.get(a [ 0]))> = A [1]' – Holger

相關問題