如果我開始的結構,可以代表你的價值觀的範圍內,這樣的:
public struct Range
{
public int Minimum { get; set; }
public int Maximum { get; set; }
}
...然後我可以代表你這樣的輸入:
var inputs = new Dictionary<string, Range>()
{
{ "a", new Range() { Minimum = 1, Maximum = 3 } },
{ "b", new Range() { Minimum = 1, Maximum = 2 } },
{ "c", new Range() { Minimum = 1, Maximum = 2 } },
};
...然後我可以生成如下結果:
Func<IEnumerable<KeyValuePair<string, Range>>, IEnumerable<Dictionary<string, int>>> build = null;
build =
kvps =>
{
if (kvps.Skip(1).Any())
{
return
from kvp in kvps.Take(1)
from n in Enumerable.Range(kvp.Value.Minimum, kvp.Value.Maximum - kvp.Value.Minimum + 1)
from r in build(kvps.Skip(1))
select new[] { new KeyValuePair<string, int>(kvp.Key, n) }.Concat(r).ToDictionary(x => x.Key, x => x.Value);
}
else
{
return
from kvp in kvps
from n in Enumerable.Range(kvp.Value.Minimum, kvp.Value.Maximum - kvp.Value.Minimum + 1)
select new[] { new KeyValuePair<string, int>(kvp.Key, n) }.ToDictionary(x => x.Key, x => x.Value);
}
};
這產生下面的字典列表:
a=1, b=1, c=1
a=1, b=1, c=2
a=1, b=2, c=1
a=1, b=2, c=2
a=2, b=1, c=1
a=2, b=1, c=2
a=2, b=2, c=1
a=2, b=2, c=2
a=3, b=1, c=1
a=3, b=1, c=2
a=3, b=2, c=1
a=3, b=2, c=2
這裏的主查詢的解釋:
from kvp in kvps.Take(1)
獲取從kvps
枚舉(這是可枚舉的 「頭」)的第一個元素
from n in Enumerable.Range(kvp.Value.Minimum, kvp.Value.Maximum - kvp.Value.Minimum + 1)
將n
的所有值從Minimum
生成爲Maximum
。
from r in build(kvps.Skip(1))
遞歸調用build
在列表的「尾部」產生的所有可能的尾巴字典
select new[] { new KeyValuePair<string, int>(kvp.Key, n) }.Concat(r).ToDictionary(x => x.Key, x => x.Value);
創建一個新的KeyValuePair<string, int>[]
與Key
和值n
並連接在每個值尾部(r
)創建一個新字典。
爲什麼迭代解決方案不夠? –
定義:「更好」 – Plutonix
你想要的是範圍的笛卡爾乘積。關於這個網站有很多問題。嘗試http://stackoverflow.com/questions/4073713/is-there-a-good-linq-way-to-do-a-cartesian-product/4073806#4073806開始。 –