使用 Linq 和 C# 创建列表中所有可能的组合

8

我有一个分类表:

 Catid | Desciption
 1 | Color
 2 | Size
 3 | Material

还有一个类别项目表格

 Catid | Name
 1 | Red
 1 | Blue
 1 | Green
 2 | Small
 2 | Med
 2 l Large
 3 | Cotton
 3 | Silk

我需要遍历所有项目并将它们显示在标签中,就像这样:

 Red Small Cotton
 Red Small Silk
 Red Med Cotton
 Red Med Silk
 Red Large Cotton
 Red Large Silk
 Blue Small Cotton
 Blue Small Silk
 Blue Med Cotton
 Blue Med Silk
 Blue Large Cotton
 Blue Large Silk
 Green Small Cotton
 Green Small Silk
 Green Med Cotton
 Green Med Silk
 Green Large Cotton
 Green Large Silk

请注意:可能会有更多或更少的类别,这并不是预先确定的。
有什么建议吗?
谢谢。

1
请注意:可能会有更多或更少的类别。这是不确定的。 - vts
2个回答

21
var result = list.GroupBy(t => t.Id).CartesianProduct();

使用CartesianProduct扩展方法,来自Eric Lippert的博客

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})); 
}

示例:

var list = new[]
{
    new { Id = 1, Description = "Red"    },
    new { Id = 1, Description = "Blue"   },
    new { Id = 1, Description = "Green"  },
    new { Id = 2, Description = "Small"  },
    new { Id = 2, Description = "Med"    },
    new { Id = 2, Description = "Large"  },
    new { Id = 3, Description = "Cotton" },
    new { Id = 3, Description = "Silk"   },
};

var result = list.GroupBy(t => t.Id).CartesianProduct();

foreach (var item in result)
{
    Console.WriteLine(string.Join(" ", item.Select(x => x.Description)));
}

输出:

Red Small Cotton
Red Small Silk
Red Med Cotton
Red Med Silk
Red Large Cotton
Red Large Silk
Blue Small Cotton
Blue Small Silk
Blue Med Cotton
Blue Med Silk
Blue Large Cotton
Blue Large Silk
Green Small Cotton
Green Small Silk
Green Med Cotton
Green Med Silk
Green Large Cotton
Green Large Silk

3
我正在撰写这个回答,给你点赞,因为你是第一个实际回答这个问题的人。 - Lukazoid
谢谢。这个几乎可以工作。但我也得到了以下结果: 红色, 蓝色, 绿色, 红色小号, 红色中号, 红色大号, 蓝色小号, 蓝色中号, 蓝色大号, 绿色小号, 绿色中号, 绿色大号, 你有什么想法可以去除这些组合吗? - vts
@user1095952:我没有得到这些结果;我的示例程序输出与上面显示的相同。请展示你的代码。 - dtb
新博客链接:https://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/ - BlueSky

17

尝试使用交叉连接(cross join):

var combo = from l1 in List1
            from l2 in List2
            select new {l1, l2};

2
在数学上,这个问题的提问者可能会觉得有趣的是:交叉连接本质上是一个笛卡尔积(即将集合A中的所有元素与集合B中的所有元素以唯一的方式组合)。 - Corbin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接