我希望在c#中获得任意数量对象的笛卡尔积。我的情况有点不寻常 - 我的输入不是基类型列表,而是具有属性列表的对象。
我的输入和输出对象如下:
public class Input
{
public string Label;
public List<int> Ids;
}
public class Result
{
public string Label;
public int Id;
}
一些示例输入数据:
var inputs = new List<Input>
{
new Input { Label = "List1", Ids = new List<int>{ 1, 2 } },
new Input { Label = "List2", Ids = new List<int>{ 2, 3 } },
new Input { Label = "List3", Ids = new List<int>{ 4 } }
};
我期望的输出对象:
var expectedResult = new List<List<Result>>
{
new List<Result>
{
new Result{Label = "List1", Id = 1},
new Result{Label = "List2", Id = 2},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 1},
new Result{Label = "List2", Id = 3},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 2},
new Result{Label = "List2", Id = 2},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 2},
new Result{Label = "List2", Id = 3},
new Result{Label = "List3", Id = 4}
}
};
如果我知道&#39;输入中的项目数量&#39;提前我可以这样做:
var knownInputResult =
from id1 in inputs[0].Ids
from id2 in inputs[1].Ids
from id3 in inputs[2].Ids
select
new List<Result>
{
new Result { Id = id1, Label = inputs[0].Label },
new Result { Id = id2, Label = inputs[1].Label },
new Result { Id = id3, Label = inputs[2].Label },
};
我正在努力使其适应任意数量的输入 - 有可能这样做吗?
答案 0 :(得分:1)
我认为这个问题的副本在评论中被链接,但由于它被重新打开并且你很难将这个问题适应你的情况,所以这是如何。
首先抓住Eric Lippert从重复问题中获取的功能(如何解释):
public static class Extensions {
public 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 })
);
}
}
然后压平你的输入。基本上只需将相应的标签附加到每个id:
var flatten = inputs.Select(c => c.Ids.Select(r => new Result {Label = c.Label, Id = r}));
然后运行笛卡尔积并完成:
// your expected result
var result = flatten.CartesianProduct().Select(r => r.ToList()).ToList();
答案 1 :(得分:0)
我并不为自己花费大量时间而感到骄傲,但它确实有效。 它基本上是黑魔法,我会在你获得的第一次机会取代它。
public static List<List<Result>> Permutate(IEnumerable<Input> inputs)
{
List<List<Result>> results = new List<List<Result>>();
var size = inputs.Select(inp => factorial_WhileLoop(inp.Ids.Count)).Aggregate((item, carry) => item + carry) - 1;
for (int i = 0; i < size; i++) results.Add(new List<Result>());
foreach (var input in inputs)
{
for (int j = 0; j < input.Ids.Count; j++)
{
for (int i = 0; i < (size / input.Ids.Count); i++)
{
var x = new Result() { Label = input.Label, Id = input.Ids[j] };
results[(input.Ids.Count * i) + j].Add(x);
}
}
}
return results;
}
public static int factorial_WhileLoop(int number)
{
var result = 1;
while (number != 1)
{
result = result * number;
number = number - 1;
}
return result;
}