我需要一种算法,它可以在List中使用任意数量的List并生成一组唯一的排列。我更喜欢找到LINQ解决方案。
我实际上有一个运行良好的Javascript函数,我正在尝试用C#重新创建它(参见底部的代码)
C#(我的尝试) - Visual Studio不喜欢我的第二个Aggregate()。它说the arguments cannot be inferred from usage
public static void testit()
{
List<List<string>> master = new List<List<string>>();
List<string> voltages = new string[] { "208", "230", "460" }.ToList();
List<string> sysConfigs = new string[] { "10205", "10210", "10215", "10220" }.ToList();
master.Add(voltages);
master.Add(sysConfigs);
var amp = master.Aggregate(
(a, b) => a.Aggregate(
(r, v) => r.Concat(
b.Select(w => new List<string>().Concat(v, w))
), new List<string>()
)
);
}
这个新集合的输出应如下所示:
/*
OUTPUT (displayed as arrays - but will be lists):
[
["208", "10205"],
["208", "10210"],
["208", "10215"],
["208", "10220"],
["230", "10205"],
["230", "10210"],
["230", "10215"],
["230", "10220"],
["460", "10205"],
["460", "10210"],
["460", "10215"],
["460", "10220"]
];
这是一个很好用的Javascript函数,我试图模仿C#:
function getPermutations(arr) {
return arr.reduce(
(a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), [])
);
}
var voltages = ["208", "230", "460"];
var sysConfigs = ["10205", "10210", "10215", "10220"];
var master = [];
master.push(voltages);
master.push(sysConfigs);
var newArr = getPermutations(master);
console.log(newArr);
答案 0 :(得分:7)
正如其他问题所述,这是笛卡尔积,而非排列。
简短版:请访问我的博客:
https://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/
长版:
两个列表的笛卡尔积以C#中的SelectMany形式或查询理解为内置。让我们从那开始。
在我们开始讨论之前,请不要这样做:
List<string> voltages = new string[] { "208", "230", "460" }.ToList()
要么这样做:
IEnumerable<string> voltages = new string[] { "208", "230", "460" };
或者这样做:
List<string> voltages = new List<string>() { "208", "230", "460" };
但是不要制作一个数组,然后列出它!只需从头开始列表。
好的,继续。我们有两个序列:
IEnumerable<string> voltages = new string[] { "208", "230", "460" };
IEnumerable<string> sysConfigs = new string[] { "10205", "10210", "10215", "10220" };
我们想要他们的笛卡儿产品:
IEnumerable<IEnumerable<string>> master =
from v in voltages
from s in sysConfigs
select new List<string>() { v, s };
我们已经完成了。
如果您不喜欢“理解形式”,那么您可以使用“流利的形式”:
IEnumerable<IEnumerable<string>> master =
voltages.SelectMany(
v => sysConfigs,
(s, v) => new List<string>() { v, s });
如果您需要列表清单:
List<List<string>> master =
voltages.SelectMany(
v => sysConfigs,
(v, s) => new List<string>() { v, s })
.ToList();
轻松自负。
此操作的含义应该清楚,但如果不是:一般形式是:
var zs =
from x in xs
from y in f(x) // f takes x and returns a collection of ys
g(x, y) // do something with every combination of x and y to make a z
在你的情况下,f(x)只是“总是产生第二个集合”,但它不一定是;该集合可能取决于x。结果是z的序列。
现在,您需要的是任意多个序列的笛卡尔积。
你直觉认为这是连接的集合是正确的。我们可以这样解决:
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] {item}));
}
请注意这是如何组合这三个操作的:select-many查询,串联和聚合。仔细研究,看看它是如何工作的。
答案 1 :(得分:1)
这是您的代码的正确版本
var amp = master.Aggregate(
new List<List<string>>(){new List<string>()},
(a, b) => a.Aggregate(
new List<List<string>>(new List<List<string>>()),
(r, v) => r.Concat(
b.Select(w => v.Concat(new List<string>{w}).ToList())
).ToList()));
答案 2 :(得分:-1)
这些不是排列(需要一个列表)。
您的输出显示两组的笛卡尔积。
这会带你到MoreLinq.Caresian(listA, listB)
MoreLinq是一个Nuget包。
代码希望
var amps = master[0]
.Cartesian(master[1], (a, b) => new List<string> { a, b } );
所以你们应该放弃master并直接使用电压和sysConfigs这样做。