假設我有以下字符串數組的數組索引:LINQ找到一個價值
string[] str = new string[] {"max", "min", "avg", "max", "avg", "min"}
是否possbile使用LINQ獲得匹配一個字符串索引列表?
作爲一個例子,我想要搜索的字符串「平均」,並獲得含有
2的列表,4
意味着「平均」可以在STR [發現2]和str [4]。
假設我有以下字符串數組的數組索引:LINQ找到一個價值
string[] str = new string[] {"max", "min", "avg", "max", "avg", "min"}
是否possbile使用LINQ獲得匹配一個字符串索引列表?
作爲一個例子,我想要搜索的字符串「平均」,並獲得含有
2的列表,4
意味着「平均」可以在STR [發現2]和str [4]。
.Select
有一個很少使用的產生索引的重載。您可以使用它像這樣:
str.Select((s, i) => new {i, s})
.Where(t => t.s == "avg")
.Select(t => t.i)
.ToList()
結果將是包含2和4
列表可以像下面這樣做:
str.Select((v,i) => new {Index = i, Value = v}) // Pair up values and indexes
.Where(p => p.Value == "avg") // Do the filtering
.Select(p => p.Index); // Keep the index and drop the value
的關鍵步驟是使用the overload of Select
將當前索引提供給函子。
您可以使用Enumerable.Select
是經過指數的過載,然後使用上一個匿名類型Enumerable.Where
:
List<int> result = str.Select((s, index) => new { s, index })
.Where(x => x.s== "avg")
.Select(x => x.index)
.ToList();
如果你只是想找到的第一個/最後一個索引,你還內建方法List.IndexOf
和List.LastIndexOf
:
int firstIndex = str.IndexOf("avg");
int lastIndex = str.LastIndexOf("avg");
(或者你可以使用this overload是採取起始索引指定起始位置)
雖然你可以使用的Select
和Where
組合,這很可能是爲使自己的功能一個很好的候選人:
public static IEnumerable<int> Indexes<T>(IEnumerable<T> source, T itemToFind)
{
if (source == null)
throw new ArgumentNullException("source");
int i = 0;
foreach (T item in source)
{
if (object.Equals(itemToFind, item))
{
yield return i;
}
i++;
}
}
不錯的選擇。我認爲一個空的'itemToFind'應該是一個合法用例,但是對不同的東西有投票權。 – recursive
你需要組合選擇並在運營商,比較公認的答案,這將是更便宜,因爲不需要中間對象:
public static IEnumerable<TResult> SelectWhere<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, bool> filter, Func<TSource, int, TResult> selector)
{
int index = -1;
foreach (var s in source)
{
checked{ ++index; }
if (filter(s))
yield return selector(s, index);
}
}
首先,您的代碼實際上並未在列表中迭代兩次,它只是迭代一次。
也就是說,你的Select實際上只是得到所有索引的序列;這是更容易與Enumerable.Range完成:
var result = Enumerable.Range(0, str.Count)
.Where(i => str[i] == "avg")
.ToList();
理解爲什麼這個列表實際上不重複兩次將需要一些時間來適應。我會盡量給出一個基本的解釋。
您應該考慮大多數LINQ方法,例如Select和Where作爲管道。每種方法都會做一些小小的工作。在Select的情況下,你給它一個方法,它實質上是這樣說的:「每當有人問我爲我的下一個項目,我會先問我的輸入序列的一個項目,然後使用我必須將其轉換爲其他東西的方法,然後把這件物品交給誰來使用我。「或多或少地說,「每當有人問我一件物品時,我會問我的輸入序列中是否有物品,如果該功能說不錯,我會把它傳下去,如果不是,我會繼續詢問物品直到我得到一個通過。「
所以,當你鏈接他們會發生什麼是ToList要求的第一個項目,它去哪裏,因爲它的第一個項目,去哪裏選擇並要求它的第一個項目,選擇去列表問它的第一個項目。該清單然後提供它的第一個項目。然後選擇將該項目轉換爲需要吐出的項目(在這種情況下,只是int 0)並將其提供給Where。哪裏需要該項目,並運行它的功能,它確定它是真實的,因此吐出0到ToList,它將它添加到列表中。那整件事再發生9次。這意味着Select將最終要求從列表中的每個項目只需要一次,並且它會將每個結果直接提供給Where,這會將「通過測試」的結果直接提供給ToList,將ToList存儲在列表中。所有的LINQ方法都經過精心設計,只有一次迭代源序列(迭代一次)。
請注意,雖然這在起初看起來很複雜,但實際上計算機很容易完成所有這些工作。這實際上並不像起初看起來那樣表現密集。
請注意,還有['Where'](http://msdn.microsoft.com/en-us/library/bb549418.aspx)提供了過載。 –
超級duper真棒謝謝你! – Jonesopolis
代碼有點聰明與哪裏 - 謝謝蒂姆! – Sven