如果我开始的结构,可以代表你的价值观的范围内,这样的:
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开始。 –