如果我从一个可以代表你的值范围的结构开始,像这样:
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)
从Minimum 到Maximum 生成n 的所有值。
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);
使用Key 和值n 创建一个新的KeyValuePair<string, int>[],并在创建新字典时连接尾部(r) 中的每个值。