【问题标题】:get a List of Max values across a list of lists获取列表列表中的最大值列表
【发布时间】:2014-03-29 18:23:52
【问题描述】:

我有一个List<List<double>>,我需要找到一个列表 MyList,例如,其中 MyList[0] 是列表中所有第一个元素的最大值。 例如,为了清楚起见: 第一个列表包含 (3,5,1),第二个包含 (5,1,8),第三个包含 (3,3,3),第四个包含 (2,0,4)。 我需要找到一个包含 (5, 5, 8) 的列表。 我不需要列表 (5,8,3,4)。

当然,我知道如何使用嵌套循环来做到这一点。 我想知道是否有 linq 方式,相信我,我不知道从哪里开始。

【问题讨论】:

  • 请展示您的非 LINQ 方法。它应该更清楚您实际想要实现的目标。
  • 所以要明确一点,您想将列表列表展平为单个列表,其中每个索引的最大值?
  • 每个列表中的项目数是否始终相同,并且每次的项目数都是恒定的?例如:您知道每个列表中总会有 x 个项目吗?
  • BateTech:我实际上是要补充一点,是的,所有列表都将始终具有相同数量的元素,但这个元素可能会有所不同。
  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。

标签: c# linq list max


【解决方案1】:
var source = new List<List<int>> {
    new List<int> { 3, 5, 1 },
    new List<int> { 5, 1, 8 },
    new List<int> { 3, 3, 3 },
    new List<int> { 2, 0, 4 }
};

var maxes = source.SelectMany(x => x.Select((v, i) => new { v, i }))
                  .GroupBy(x => x.i, x => x.v)
                  .OrderBy(g => g.Key)
                  .Select(g => g.Max())
                  .ToList();

返回{ 5, 5, 8},这是您需要的。当源列表也有不同数量的元素时也可以工作。

奖金

如果你也需要Min 的版本,并且想防止代码重复,你可以去一点功能:

private static IEnumerable<TSource> GetByIndex<TSource>(IEnumerable<IEnumerable<TSource>> source, Func<IEnumerable<TSource>, TSource> selector)
{
    return source.SelectMany(x => x.Select((v, i) => new { v, i }))
                 .GroupBy(x => x.i, x => x.v)
                 .OrderBy(g => g.Key)
                 .Select(g => selector(g));
}

public static IEnumerable<TSource> GetMaxByIndex<TSource>(IEnumerable<IEnumerable<TSource>> source)
{
    return GetByIndex(source, Enumerable.Max);
}

public static IEnumerable<TSource> GetMinByIndex<TSource>(IEnumerable<IEnumerable<TSource>> source)
{
    return GetByIndex(source, Enumerable.Min);
}

【讨论】:

  • Marcin,也感谢您的回答。它正在工作,这意味着它提供了正确的解决方案,也感谢您的奖金。不幸的是,从我的测试来看,它似乎比 Christos 的答案慢得多(10 倍或 20 倍),即使你的答案更干净、更优雅。
【解决方案2】:

试试这个:

 // Here I declare your initial list.
 List<List<double>> list = new List<List<double>>()
 {
     new List<double>(){3,5,1},
     new List<double>(){5,1,8},
     new List<double>(){3,3,3},
     new List<double>(){2,0,4},
 };

 // That would be the list, which will hold the maxs.
 List<double> result = new List<double>();


 // Find the maximum for the i-st element of all the lists in the list and add it 
 // to the result.
 for (int i = 0; i < list[0].Count-1; i++)
 {
     result.Add(list.Select(x => x[i]).Max());
 }

注意:此解决方案仅在列表中包含的所有列表具有相同数量的元素时才有效。

【讨论】:

  • Christos,首先感谢您的回答。我选择(到目前为止)您的答案,因为它比简单的嵌套 for(当有很多数据时)更快,并且比提出的其他解决方案快得多.我认为您的解决方案中有错字,我想您需要编写 list[0].count-1 。不幸的是,您的解决方案仅在所有列表具有相同长度时才有效,但是正如我在 cmets 中所写的那样,这是我的情况,所以没关系。有没有办法在您的解决方案中将这个“for”也写为 linq 语句?不是要求,只是出于好奇
  • @JohannesWentu 使用var result = Enumerable.Range(0, list.Length).Select(i =&gt; list.Max(x =&gt; x[i])).ToList(); 摆脱for 循环。
  • @Johannes Wentu 感谢您让我知道我的错误。看到Marcin的评论,我会说我会使用这个,以避免使用for。
【解决方案3】:

即使这个话题很久以前就有答案了,我想在这里放另一个我用 Linq 编造的解决方案,比这个 other solution 短:

List<List<int>> mylist; //initial list of list

List<List<int>> mins_list = mylist.Aggregate(
    (x, cur) => cur.Zip(x, (a, b) => (a.Value > b.Value) ? a : b).ToList()
).ToList();

这个非常简单的代码只是将每个子列表聚合成一个最小值列表。请注意,内部 ToList 是强制性的,因为 Zip 是延迟的。

您可以将代码封装在扩展方法中,并使用与 MarcinJuraszek 相同的技巧来生成其他类似的计算(最小值、最大值、平均值、标准差...)。

【讨论】:

    【解决方案4】:

    如果您始终知道列表中有多少元素,则可以使用以下方法:

    var result =  new[]
            {
                list.Select(a => a[0]).Max(), 
                list.Select(a => a[1]).Max(),
                list.Select(a => a[2]).Max()
            };
    

    【讨论】:

      猜你喜欢
      • 2016-01-21
      • 2019-02-13
      • 1970-01-01
      • 1970-01-01
      • 2020-09-22
      • 1970-01-01
      • 2022-01-25
      • 2017-06-29
      • 2019-05-29
      相关资源
      最近更新 更多