动态笛卡尔积
Dynamic Cartesian Product
class 演示:
class item
{
public string name { get; set; }
public int level { get; set; }
}
数据演示:
List<item> all = new List<item>();
all.Add(new item { name = "Red", level = 0 });
all.Add(new item { name = "Blue", level = 0 });
all.Add(new item { name = "S", level = 1 });
all.Add(new item { name = "M", level = 1 });
all.Add(new item { name = "L", level = 1 });
all.Add(new item { name = "Man", level = 2 });
all.Add(new item { name = "Woman", level = 2 });
我需要按 level 分组并组合所有 name ,这是笛卡尔积的问题。
结果是这样的:
Red - S - Man
Red - S - Woman
Red - M - Man
Red - M - Woman
Red - L - Man
Red - L - Woman
Blue - S - Man
Blue - S - Woman
Blue - M - Man
Blue - M - Woman
Blue - L - Man
Blue - L - Woman
如果水平是固定的,用下面的代码解决:
foreach(var _0 in all.Where(m => m.level == 0))
{
foreach(var _1 in all.Where(m => m.level == 1))
{
foreach(var _2 in all.Where(m => m.level == 2))
{
Console.WriteLine(_0.name + "-" + _1.name + "-" + _2.name);
}
}
}
但最大的问题是:级别是动态的,我只是这样编码:
for(int i = 0; i < level; i++)
{
//some code ...
}
因为我的真实项目是Javascript,所以请给我简单的代码(非linq),非常感谢帮助。
像这样的东西应该可以工作:
var lines = CartesianProduct(all, 0);
foreach(var line in lines) {
Console.WriteLine(line);
}
List<string> CartesianProduct(List<item> items, int level) {
List<string> result = new List<string>();
List<string> itemsOnThisLevel = new List<string>();
foreach(var it in items) {
if (it.level == level) itemsOnThisLevel.Add(it.name);
}
if (!itemsOnThisLevel.Any()) {
result.Add("");
return result;
}
var itemsOnLowerLevels = CartesianProduct(items, level+1);
foreach(var it in itemsOnThisLevel) {
foreach(var it2 in itemsOnLowerLevels) {
result.Add(it2 + " - " + it);
}
}
return result
}
编辑:按照作者的要求删除了 linq 表达式。
我将从构建一个包含每个级别项目的列表开始:
var levels = new List<List<item>>();
foreach (var item in all)
{
while (levels.Count <= item.level)
levels.Add(new List<item>());
levels[item.level].Add(item);
}
然后使用简单的递归方法填充结果:
var result = new List<string>();
AddCombinations(result, levels, 0, null);
其中的方法是:
static void AddCombinations(List<string> result, List<List<item>> levels, int level, string path)
{
if (level >= levels.Count)
{
result.Add(path);
return;
}
foreach (var item in levels[level])
AddCombinations(result, levels, level + 1, path == null ? item.name : path + " - " + item.name);
}
如果您愿意,我可以根据我对 的回答调整实现,而不是递归,以在适当的位置迭代构建结果,但我认为以上内容应该足够了。
class 演示:
class item
{
public string name { get; set; }
public int level { get; set; }
}
数据演示:
List<item> all = new List<item>();
all.Add(new item { name = "Red", level = 0 });
all.Add(new item { name = "Blue", level = 0 });
all.Add(new item { name = "S", level = 1 });
all.Add(new item { name = "M", level = 1 });
all.Add(new item { name = "L", level = 1 });
all.Add(new item { name = "Man", level = 2 });
all.Add(new item { name = "Woman", level = 2 });
我需要按 level 分组并组合所有 name ,这是笛卡尔积的问题。 结果是这样的:
Red - S - Man
Red - S - Woman
Red - M - Man
Red - M - Woman
Red - L - Man
Red - L - Woman
Blue - S - Man
Blue - S - Woman
Blue - M - Man
Blue - M - Woman
Blue - L - Man
Blue - L - Woman
如果水平是固定的,用下面的代码解决:
foreach(var _0 in all.Where(m => m.level == 0))
{
foreach(var _1 in all.Where(m => m.level == 1))
{
foreach(var _2 in all.Where(m => m.level == 2))
{
Console.WriteLine(_0.name + "-" + _1.name + "-" + _2.name);
}
}
}
但最大的问题是:级别是动态的,我只是这样编码:
for(int i = 0; i < level; i++)
{
//some code ...
}
因为我的真实项目是Javascript,所以请给我简单的代码(非linq),非常感谢帮助。
像这样的东西应该可以工作:
var lines = CartesianProduct(all, 0);
foreach(var line in lines) {
Console.WriteLine(line);
}
List<string> CartesianProduct(List<item> items, int level) {
List<string> result = new List<string>();
List<string> itemsOnThisLevel = new List<string>();
foreach(var it in items) {
if (it.level == level) itemsOnThisLevel.Add(it.name);
}
if (!itemsOnThisLevel.Any()) {
result.Add("");
return result;
}
var itemsOnLowerLevels = CartesianProduct(items, level+1);
foreach(var it in itemsOnThisLevel) {
foreach(var it2 in itemsOnLowerLevels) {
result.Add(it2 + " - " + it);
}
}
return result
}
编辑:按照作者的要求删除了 linq 表达式。
我将从构建一个包含每个级别项目的列表开始:
var levels = new List<List<item>>();
foreach (var item in all)
{
while (levels.Count <= item.level)
levels.Add(new List<item>());
levels[item.level].Add(item);
}
然后使用简单的递归方法填充结果:
var result = new List<string>();
AddCombinations(result, levels, 0, null);
其中的方法是:
static void AddCombinations(List<string> result, List<List<item>> levels, int level, string path)
{
if (level >= levels.Count)
{
result.Add(path);
return;
}
foreach (var item in levels[level])
AddCombinations(result, levels, level + 1, path == null ? item.name : path + " - " + item.name);
}
如果您愿意,我可以根据我对