天天看點

Linq中帶有疊代索引的Select擴充方法,為啥知道的人不多呢?

一:背景

昨天在看C#函數式程式設計這本書的時候,有一處讓我幹着急,需求是這樣: 給多行文字加上數字清單項。

Linq中帶有疊代索引的Select擴充方法,為啥知道的人不多呢?

針對這個需求你會如何快捷高效的給每個項目加上數字編号呢? 我看書中是這樣實作的,如下代碼

public class Program
    {
        public static void Main(string[] args)
        {
            var list = new List<string>()
            {
                "cnblogs","csdn","zhihu","oschina"
            };

            var items = list.Zip(Enumerable.Range(1, list.Count + 1), (item, i) => $"{i}. {item}").ToList();

            items.ForEach(Console.WriteLine);
        }
    }

------------------- output -------------------
1. cnblogs
2. csdn
3. zhihu
4. oschina
Press any key to continue . . .

           

怎麼說呢,需求能實作沒有問題,但這裡還是累贅了,因使用到了拉鍊函數Zip 和生成範圍的Range,全糾纏到一塊,有沒有更簡單粗暴的方式呢? 其實你隻用Select的一個帶疊代變量的重載方法就可以搞定,但現實中還是有很多的程式員不會使用或者說不知道,是以優化後的代碼如下。

var items = list.Select((item, i) => $"{i + 1}. {item}").ToList();

------------------- output -------------------
1. cnblogs
2. csdn
3. zhihu
4. oschina
Press any key to continue . . .

           

二:源碼探究

相信編碼多年的我們無數次的在憎恨foreach沒有帶上索引,這麼普羅大衆的需求盡然都沒有實作,而python這樣的語言早就給實作了,為了解決這個不足,我還得需要單獨定義一個變量在疊代時即時記錄,煩不勝煩,就像下面這樣。

var index = 0;

            foreach (var item in list)
            {
                index++;
                Console.WriteLine(item);
            }
           

可能FCL類庫程式員也深有體會,是以加了一個可以在疊代中擷取目前index的絕妙方法,這麼🐮👃造福人類的方法卻發現身邊知道的人少之又少,小遺憾哈。

1. ILSpy檢視源碼

從下面代碼的 SelectIterator 枚舉類可以看到,其實在底層也是單獨給你定義了一個index,然後逐一回調給你的回調函數,這種封裝很有必要,不過全是高階函數,功底很深哈!

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
	if (source == null)
	{
		throw Error.ArgumentNull("source");
	}
	if (selector == null)
	{
		throw Error.ArgumentNull("selector");
	}
	return SelectIterator(source, selector);
}

private static IEnumerable<TResult> SelectIterator<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
	int index = -1;
	foreach (TSource item in source)
	{
		index = checked(index + 1);
		yield return selector(item, index);
	}
}

           

三:其他案例

其實有太多例子需要使用疊代器中的index值了,比如最近業務中要計算各個月份的環比率,用今天講到的這個方法就可以非常完美的解決,簡化後的代碼如下。

public static void Main(string[] args)
        {
            var list = new List<int>()
            {
                10, 20, 30,40,50, 60,70,80,90,100,110,120,
            };

            var rateList = list.Select((item, index) =>
            {
                return index == 0 ? 0 : Math.Round(((decimal)list[index] - list[index - 1]) / list[index - 1], 2);
            }).ToList();

            rateList.ForEach(Console.WriteLine);
        }

------------------- output -------------------
0
1
0.5
0.33
0.25
0.2
0.17
0.14
0.12
0.11
0.1
0.09
Press any key to continue . . .

           

好了,本篇來自于觸景生情,希望對您編碼有幫助。

如您有更多問題與我互動,掃描下方進來吧~

Linq中帶有疊代索引的Select擴充方法,為啥知道的人不多呢?
Linq中帶有疊代索引的Select擴充方法,為啥知道的人不多呢?