使用 LINQ 获取列表中的所有对

Posted

技术标签:

【中文标题】使用 LINQ 获取列表中的所有对【英文标题】:Get all pairs in a list using LINQ 【发布时间】:2011-11-06 16:58:40 【问题描述】:

如何获得列表中所有可能的项目对(顺序不相关)?

例如如果我有

var list =  1, 2, 3, 4 ;

我想得到这些元组:

var pairs = 
   new Tuple(1, 2), new Tuple(1, 3), new Tuple(1, 4),
   new Tuple(2, 3), new Tuple(2, 4)
   new Tuple(3, 4)

【问题讨论】:

1, 1, 1, 1 列表的期望输出是什么?六个(1, 1) 还是一个(1, 1) 【参考方案1】:

对 cgeers 答案稍作重新表述,以获得所需的元组而不是数组:

var combinations = from item1 in list
                   from item2 in list
                   where item1 < item2
                   select Tuple.Create(item1, item2);

(如果需要,请使用 ToListToArray。)

以非查询表达式形式(稍微重新排序):

var combinations = list.SelectMany(x => list, (x, y) => Tuple.Create(x, y))
                       .Where(tuple => tuple.Item1 < tuple.Item2);

这两个实际上都会考虑 n2 个值而不是 n2/2 个值,尽管它们最终会得到正确的答案。另一种选择是:

var combinations = list.SelectMany((x, i) => list.Skip(i + 1), (x, y) => Tuple.Create(x, y));

...但这使用了Skip,可能没有被优化。老实说,这可能无关紧要 - 我会选择最适合您使用的那个。

【讨论】:

Jon,这将创建Tuple (1,1),它不是一对。 谢谢,这是最好的解决方案。 (但是,你的意思是Skip(x.index + 1)?) 是的,Except(..) 是不必要的,因为 where 子句负责处理。【参考方案2】:

计算笛卡尔积以确定所有可能的组合。

例如:

var combinations = from item in list
                   from item2 in list
                   where item < item2
                   select new[]  item, item2 ;

您可以在此处找到有关使用 LINQ 计算笛卡尔积的更多信息:

http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx

然后您可以将其转换为 Tuple 对象的集合。

var pairs = new List<Tuple<int, int>>();
foreach (var pair in combinations)

    var tuple = new Tuple<int, int>(pair[0], pair[1]);
    pairs.Add(tuple);

简而言之:

var combinations = (from item in list
                    from item2 in list
                    where item < item2
                    select new Tuple<int, int>(item, item2)).ToList();

【讨论】:

1. 这将创建一个可枚举的列表。这真的是你的意思吗?为什么不只是select Tuple.Create(item, item2)2. 这将导致重复对,例如(1,4)(4,1)。不确定这是否是 OP 想要的,但看起来不像。 它还会创建(1,1),这在OPs示例中没有说明,也不是一对。但我想知道(1,4)(4,1) 是否重要。 @stakx @Mikael 所有重复的都可以被where item &lt; item2过滤掉。 感谢您的反馈。更新了我的答案以过滤掉重复项。 @Laroslav 仅当项目是为了开始,对吧?【参考方案3】:

你可以这样解决:

 var list = new[]  1, 2, 3, 4 ;

 var pairs = from l1 in list
             from l2 in list.Except(new[]  l1 )
             where l1 < l2
             select new  l1, l2 ;

 foreach (var pair in pairs)
 
    Console.WriteLine(pair.l1 + ", " + pair.l2);
 

【讨论】:

以上是关于使用 LINQ 获取列表中的所有对的主要内容,如果未能解决你的问题,请参考以下文章

使用 Linq 从列表中获取所有匹配值的索引

获取外键表的所有列以及 LINQ 中的主表列

使用LINQ获取List列表中的某个字段值

使用 LINQ 获取两个比较列表的结果并根据结果更改列表中的属性

使用 LINQ 排序后获取集合中项目的新索引

使用 Linq C# 获取元组对象列表中的最新日期对象