如何根据特定的组合逻辑将列表字典转换为唯一字典列表?
How to convert a dictionary of lists into a list of unique dictionaries according to a particular combinatorial logic?
我有一个这样的列表字典:
var dictOfLists = new Dictionary<string, List<string>>
{
["foo"] = new List<string>{ "a", "b", "c" },
["bar"] = new List<string>{ "d" },
["baz"] = new List<string>{ "e", "a" }
}
我想将其转换为独特词典的列表,如下所示:
var listOfUniqDicts = new List<Dictionary<string, string>>
{
new Dictionary<string, string> {["foo"] = "a", ["bar"] = "d", ["baz"] = "e" },
new Dictionary<string, string> {["foo"] = "a", ["bar"] = "d", ["baz"] = "a" },
new Dictionary<string, string> {["foo"] = "b", ["bar"] = "d", ["baz"] = "e" },
new Dictionary<string, string> {["foo"] = "b", ["bar"] = "d", ["baz"] = "a" },
new Dictionary<string, string> {["foo"] = "c", ["bar"] = "d", ["baz"] = "e" },
new Dictionary<string, string> {["foo"] = "c", ["bar"] = "d", ["baz"] = "a" },
}
(如您所见,在上面的列表中,每个字典代表一个唯一的值组合,其键映射到初始字典的相应键。)
是否有一个干净的算法可以使用上述类型的任意字典来执行此操作?
这就像构建一个真理table:
- 在第一列中写真、假、真、假...
- 在第二列中,您将每个项目重复 2 次:true、true false、false、true、true、false、false ...
- 在第 n 列中,您将每个项目重复 2^(n-1) 次
此问题为通用版(try in dotnetfiddle):
private Dictionary<TKey, TValue>[] BuildDictionary<TKey, TValue>(Dictionary<TKey, List<TValue>> dict) where TKey : notnull
{
// Calculating the size of the result (product of the length of each entry)
int[] lengths = dict.Select(d => d.Value.Count()).ToArray();
int size = lengths.Aggregate(1, (prev, val) => prev * val); // reduce in JavaScript
var result = new Dictionary<TKey, TValue>[size];
for (int i = 0; i < result.Length; i++) { result[i] = new Dictionary<TKey, TValue>(); }
int repeats = 1;
foreach (var d in dict)
{
var key = d.Key;
for (int row = 0; row < size;)
for (int i = 0; i < repeats; i++)
foreach (var val in d.Value)
{
result[row].Add(key, val);
row++;
}
repeats *= d.Value.Count;
}
return result;
}
结果:
[
{"foo":"a","bar":"d","baz":"e"},
{"foo":"b","bar":"d","baz":"a"},
{"foo":"c","bar":"d","baz":"e"},
{"foo":"a","bar":"d","baz":"a"},
{"foo":"b","bar":"d","baz":"e"},
{"foo":"c","bar":"d","baz":"a"}
]
我有一个这样的列表字典:
var dictOfLists = new Dictionary<string, List<string>>
{
["foo"] = new List<string>{ "a", "b", "c" },
["bar"] = new List<string>{ "d" },
["baz"] = new List<string>{ "e", "a" }
}
我想将其转换为独特词典的列表,如下所示:
var listOfUniqDicts = new List<Dictionary<string, string>>
{
new Dictionary<string, string> {["foo"] = "a", ["bar"] = "d", ["baz"] = "e" },
new Dictionary<string, string> {["foo"] = "a", ["bar"] = "d", ["baz"] = "a" },
new Dictionary<string, string> {["foo"] = "b", ["bar"] = "d", ["baz"] = "e" },
new Dictionary<string, string> {["foo"] = "b", ["bar"] = "d", ["baz"] = "a" },
new Dictionary<string, string> {["foo"] = "c", ["bar"] = "d", ["baz"] = "e" },
new Dictionary<string, string> {["foo"] = "c", ["bar"] = "d", ["baz"] = "a" },
}
(如您所见,在上面的列表中,每个字典代表一个唯一的值组合,其键映射到初始字典的相应键。)
是否有一个干净的算法可以使用上述类型的任意字典来执行此操作?
这就像构建一个真理table:
- 在第一列中写真、假、真、假...
- 在第二列中,您将每个项目重复 2 次:true、true false、false、true、true、false、false ...
- 在第 n 列中,您将每个项目重复 2^(n-1) 次
此问题为通用版(try in dotnetfiddle):
private Dictionary<TKey, TValue>[] BuildDictionary<TKey, TValue>(Dictionary<TKey, List<TValue>> dict) where TKey : notnull
{
// Calculating the size of the result (product of the length of each entry)
int[] lengths = dict.Select(d => d.Value.Count()).ToArray();
int size = lengths.Aggregate(1, (prev, val) => prev * val); // reduce in JavaScript
var result = new Dictionary<TKey, TValue>[size];
for (int i = 0; i < result.Length; i++) { result[i] = new Dictionary<TKey, TValue>(); }
int repeats = 1;
foreach (var d in dict)
{
var key = d.Key;
for (int row = 0; row < size;)
for (int i = 0; i < repeats; i++)
foreach (var val in d.Value)
{
result[row].Add(key, val);
row++;
}
repeats *= d.Value.Count;
}
return result;
}
结果:
[
{"foo":"a","bar":"d","baz":"e"},
{"foo":"b","bar":"d","baz":"a"},
{"foo":"c","bar":"d","baz":"e"},
{"foo":"a","bar":"d","baz":"a"},
{"foo":"b","bar":"d","baz":"e"},
{"foo":"c","bar":"d","baz":"a"}
]