2016-02-13 55 views
1

列表連續兩個項目的子列表假設我們有一個像如何找到在使用LINQ

"A", "B", "C", "D", "E", "F" 

現在的字符串列表,我想尋找的子列表兩個連續項目D E在此列表中。我如何使用Linq來做到這一點?

我的做法是:

int i = list.FindIndex(x => x == "D"); 
int j = list.FindIndex(x => x == "E"); 

int p = i < 0 || j < 0 ? -1 : (j == i + 1 ? i : -1); 

它是一個正確的解決方案?有沒有更短的解決方案?

+1

你可以使用列表,其中((X,I)=>(X = = 「d」)&&(名單[我+ 1] ==「E」))。FirstOrDefault(); – jdweng

+0

@jdweng太棒了!爲什麼你不把它作爲答案? – Ahmad

回答

3

你可以重寫你的方法如下:

bool hasSublist = list 
    .SkipWhile(x => x != "D") 
    .Take(2) 
    .SequenceEquals(new[] {"D", "E"}); 

如果需要的{"D", "E"}開始索引,你可以添加一個選擇對了字母和它們的索引。

但是,你們的做法的問題是,它會錯過子,如果有另一個"D"不是跟一個"E",例如

"D" "A" "D" "B" "D" "C" "D" "D" "D" "E" 

有在最後一個"D" "E",但經過你的方法停止找到第一個"D"

如果您正在尋找長度爲2的子列表,你可以使用Zip,像這樣:

bool hasSublist = list 
    .Zip(list.Skip(1), (a, b) => new {a, b}) 
    .Any(p => p.a == "D" && p.b == "E"); 

但是,這不能擴展更長的子列表。

使用純for循環將運行得更好:

for (var i = 0 ; i < list.Count-1 ; i++) { 
    if (list[i] == "D" && list[i+1] == "E") { 
     ... 
    } 
} 

if內可以用SequenceEquals被替換,可容納任何長度的子列表:

var desiredSublist = new[] {"D", "E", "F"}; 
for (var i = 0 ; i < list.Count-desiredSublist+1 ; i++) { 
    if (list.Skip(i).SequenceEquals(desiredSublist)) { 
     ... 
    } 
} 
1

我不認爲LINQ在這裏是適當的。

更有效的解決辦法是找到"D"然後就檢查它是不是在年底和"E"是下一個索引:

int i = list.FindIndex(x => x == "D"); 
int p = (i < list.Count - 1) && (list[i + 1] == "E") ? i : -1; 

這避免了循環兩次,發現這兩個指數,也如果"E"出現在"D"旁邊,但在它之前仍然匹配,例如{"E", "C", "D", "E"}

0

不是一個很好的通用或有效的答案,但簡潔 - 因爲它是一個字符串/字符列表,你可以做一個簡單的string.Join()並檢查子字符串:

int p = string.Join("", list).IndexOf("DE"); 
+0

是的,如果我認爲字符串只是一個字母,如果列表是{「DE」,「B」,「C」} – Ahmad

1

我沒有看到比您更短的解決方案。但我認爲你提出的解決方案只有在第一個字符串沒有在列表中出現兩次時才起作用。 例如,如果列表是:

"A", "D", "B", "C", "D", "E", "F" 

我覺得你的建議是行不通的,因爲第一FindIndex將返回第一個「d」,這後面沒有「E」的指數。

一個更多鈔票替代可(應進行測試,以確保):

int index=-1; 
    Parallel.For(0, list.Count - 1, i => 
    { 
     if (list[i] == "D" && list[i + 1] == "E") 
     { 
      Interlocked.Exchange(ref index, i); 
     } 
    }); 
//after the loop, if index!=-1, sublist was found and starts at index position 

爲不短,當然,但可以更快,如果列表是非常大的,因爲使用的Parallel.For。一個限制是,如果子列表出現好幾次,你可以獲得它們中任何一個的索引(不一定是第一個索引)。

1

最優雅的解決方案是最簡單的

Where((x,i) => (x == "D") && (i != list.Count - 1) && (list[i + 1] == "E")).FirstOrDefault();

+0

那就更好了:-) – dasblinkenlight

+0

但是這一個與檢查最後項目。 – jdweng