我正在嘗試使用 Linq 以Dictionary<string, Dictionary<string, List>>
這種方式對型別的字典進行分組,以便外鍵成為內鍵,反之亦然。
這是我得到的最接近的
Dictionary<IEnumerable<string>, Dictionary<string, List>> reversed =
nodeTypedContainer
.GroupBy(kv =>
{
IEnumerable<string> keys = kv.Value.Keys.Select(x => x);
return keys;
}, kv =>
{
return new
{
Values = kv.Value.Values.SelectMany(x => x.ToList()),
Node = kv.Key
};
})
.ToDictionary(
group =>
{
return group.Key;
},
group =>
{
return group
.Select(x => (x.Containers, x.Node))
.GroupBy(x => x.Node, x => x.Containers)
.ToDictionary(x => x.Key, x => x.SelectMany(q => q));
});
nodeTypedContainer 在哪里
Dictionary<string, Dictionary<string, IEnumerable<V1Container>>>
所以外鍵是一個 IEnumerable,這是有道理的,因為如果我最初有一個這樣的字典
[
{
key: node1,
value: [{
key: k1
value: [1, 2, 3]
},{
key: k2
value: [2]
]
},
{
key: node2,
value: [{
key: k1
value: [3]
}]
}
]
反轉應該是
[
{
key: k1,
value: [{
key: node1
value: [1, 2, 3]
},{
key: node2
value: [3]
}]
},
{
key: k2,
value: [{
key: node1
value: [2]
}]
},
]
uj5u.com熱心網友回復:
有趣的是,我想……我會使用 SelectMany 將嵌套擴展為 a { key1, key2, value },然后使用 Aggregate 將其重新組合在一起,而不是 GroupBy/ToDictionary
var r = nodeTypedContainer
.SelectMany(
kvpO => kvpO.Value,
(kvpO, kvpI) => new { KeyO = kvpO.Key, KeyI = kvpI.Key, kvpI.Value }
)
.Aggregate(
new Dictionary<string, Dictionary<string, List<int>>>(),
(seed, val) => {
if (seed.TryGetValue(val.KeyI, out var dictI))
dictI.Add(val.KeyO, val.Value);
else
seed[val.KeyI] = new() { { val.KeyO, val.Value } };
return seed;
}
);
Aggregate 和在較小程度上 SelectMany,我認為不經常使用,所以它可能需要解釋一下。
帶一個引數的 SelectMany 非常簡單:它將 T[][] 轉換為 T[] 因此一些嵌套的串列串列(就像一個人的串列,每個人都有一個寵物的串列)成為嵌套串列的直接串列物品(10 個人每人有 20 只寵物,變成 1 份 200 只寵物)。
帶有兩個引數的 SelectMany 允許我們訪問原始人以及寵物串列,這意味著我們可以訪問較高級別的巢以及較低級別的巢。這意味著我們可以列出 200 只寵物,每個人也重復 20 次
在這種情況下,它會轉換資料:
[
{
key: node1,
value: [{
key: k1
value: [1, 2, 3]
},{
key: k2
value: [2]
]
},
{
key: node2,
value: [{
key: k1
value: [3]
}]
}
]
變成類似的東西:
{ node1, k1, [1, 2, 3] }
{ node1, k2, [2] }
{ node2, k1, [3] }
現在沒有等級制度;而是重復 node1。
然后我們使用 Aggregate 將其重新組合在一起
- Aggregate 的第一個引數是
Dictionary<string, Dictionary<string, List<int>>>我們將輸出的新引數。它最初是一個空字典,我們將在遍歷每個未嵌套的專案時構建它。 - Aggregate 的第二個引數應該是一些修改當前累積值并回傳它的代碼。我們實際上并不需要一個回傳它的版本,因為我們總是修改我們創建的種子的內容,而不是具有不可變的樣式“接受當前迭代,基于它準備一個新版本并在下次回傳它”。在某種程度上,它與“LINQ 不應有副作用”背道而馳,但在 Aggregate 上人們普遍接受它會產生這種副作用,并且從我們正在修改我們在種子中創建的實體的意義上說,這是安全的。警惕在除第一個引數之外的其他地方創建的可變內容上使用 Aggregate
所以第二個 arg 的 lambda 接收到新的 Dict<Dict>; 它來查找外字典是否包含在內鍵(如K1,K2)。如果它不那么它應該添加外鍵和內部串列作為一個新的條目。如果沒有,那么它應該創建一個用外部鍵和內部 List初始化的新內部 Dictionary<string, List>
uj5u.com熱心網友回復:
這是我能想到的最直接的方法:
Dictionary<string, Dictionary<string, List<int>>> reversed =
(
from kv1 in nodeTypedContainer
from kv2 in kv1.Value
select new { k1 = kv1.Key, k2 = kv2.Key, v = kv2.Value}
)
.ToLookup(x => x.k2)
.ToDictionary(x => x.Key, x => x.ToDictionary(y => y.k1, y => y.v));
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/380059.html
