[英]How do I combine the keys and values of a Dictionary into one List using LINQ?
我有一個字典,其中鍵是一個字符串,值是與該鍵對應的字符串列表。 我想顯示字典中的所有鍵,其中與該鍵相關聯的值標簽在該鍵下方。 像這樣的東西:
Key 1
Value 1
Value 2
Value 3
Key 2
Value 1
Value 2
在C#2.0中,我會這樣做( values
是Dictionary
):
StringBuilder sb = new StringBuilder();
foreach(KeyValuePair<string, List<string>> pair in values)
{
sb.AppendLine(pair.Key);
foreach(string item in pair.Value)
{
sb.AppendLine('\t' + item);
}
}
我如何使用LINQ進行等效操作? 似乎它應該是可能的,但我無法弄清楚如何做到這一點。
如果我使用values.SelectMany(p => p.Values)
,那么只有值將在最終結果中,而不是鍵。
我想到的任何其他解決方案都有類似的限制。
以下是使用聚合擴展方法的解決方案:
string result = values.Aggregate("",
(keyString, pair) =>
keyString + "\n" + pair.Key + ":"
+ pair.Value.Aggregate("",
(str, val) => str + "\n\t" + val)
);
C#中的聚合子句沒有LINQ語法(但顯然在Visual Basic中有一些預定義的函數)。
這個解決方案可能看起來有點復雜,但聚合方法非常有用。
它的工作原理如下:如果你有一個List<int>
你可以將所有值組合成一個聚合值 。
這與Select
方法形成對比,后者不會修改列表的長度。 或者Where
方法,它會縮小列表,但它仍然是一個列表(而不是單個值)。
例如,如果您有一個列表{1, 2, 3, 4}
您可以將它們組合成一個值,如下所示:
int[] xs = {1, 2, 3, 4};
int sum = xs.Aggregate(0, (sumSoFar, x) => sumSoFar + x);
所以你給Aggregate
方法賦予兩個值; 種子值和'組合器'功能:
0
)。 x
。 簡而言之, Aggregate
方法如何在List<int>
。 它在KeyValuePair<string, List<string>>
上的工作方式相同,但只是使用不同的類型。
我不確定你是怎么在LINQ中做的,但是使用lambdas你可以做類似的事情:
string foo = string.Join(Environment.NewLine,
values.Select(k => k.Key + Environment.NewLine +
string.Join(Environment.NewLine,
k.Value.Select(v => "\t" + v).ToArray())).ToArray());
但這並不是非常易讀。
LINQ中沒有任何內容可以幫助您,因為您對值的要求與對鍵的要求不同(您在值之間切換)。
即使情況並非如此,充其量只是LINQ會幫助你只需要一個枚舉源來循環,你必須要有一些分區邏輯,以指示你何時處理一個集合價值與關鍵。
它歸結為你已經為你提供了一個自然分組,除非你正在處理除分組(排序,投影,過濾)以外的操作,否則LINQ將無法再提供幫助。
如果您有這樣的方法:
public IEnumerable<string> GetStrings
(KeyValuePair<string, List<string>> kvp)
{
List<string> result = new List<string>();
result.Add(kvp.Key);
result.AddRange(kvp.Value.Select(s => "\t" + s));
return result;
}
然后你可以這樣做:
List<string> result = theDictionary
.SelectMany(kvp => GetStrings(kvp)).ToList();
或者一般來說:
public static IEnumerable<T> GetFlattened<T, U>
( this KeyValuePair<T, List<U>> kvp,
Func<U, T> ValueTransform
)
{
List<T> result = new List<T>();
result.Add(kvp.Key);
result.AddRange(kvp.Value.Select(v => ValueTransform(v)));
return result;
}
List<string> result = theDictionary
.SelectMany(kvp => kvp.GetFlattened(v => "\t" + v))
.ToList();
我會對值進行選擇,將項目放在初始列表中(使用string.Join作為值),然后將其彈出到字符串中(再次使用string.Join)。
IEnumerable<string> items = values.Select(v =>
string.Format("{0}{1}{2}", v.Key, Environment.NewLine + "\t",
string.Join(Environment.NewLine + "\t", v.Value.ToArray()));
string itemList = string.Join(Environment.NewLine, items.ToArray());
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.