【问题标题】:The most efficient way to get object with max value from list of objects从对象列表中获取具有最大值的对象的最有效方法
【发布时间】:2015-08-11 00:07:54
【问题描述】:

我有一个名为 entry 的对象。它在浮点数中具有最小值和最大值,在字符串中具有文件名。这些对象存储在一个列表中

List<Entry> minMaxList = new List<Entry>();

我需要找到一个具有最大值和最小值的对象及其文件名。

如果我有这样的数组

       Entry1                    Entry2                  Entry3
min  max    filename        min  max    filename      min  max    filename
| 2 | 120 |  file1.txt |  | 2 | 150 |  file1.txt |  | 5 | 150 |  file1.txt |     

我想得到最低值的对象是Entry1和Entry2,最高值的对象是Entry2和Entry3

我试过了:

var max =  minMaxList.Max(r => r.getMax())

这很好用,但它返回一个值,没有任何其他关于它来自哪里的信息。我需要整个对象,或者至少需要这个值所在的文件名。我想知道它是否可以在单个命令中完成,或者我是否必须再次迭代列表并根据之前选择的最小值和最大值找到所有条目。

【问题讨论】:

  • 您的性能限制是什么? LINQ Max 和 Min 扩展方法是否太慢?您是否要对同一数据多次执行此查找?
  • 这是我将在程序中只执行一次的最后一个任务。 LINQ 应该没问题。
  • 也许可以使用聚合在一个简单的命令中完成。
  • 你实现了getmax()???以及您为什么要费心实施它
  • 你为什么要提出一个单一陈述、有效答案的问题,然后接受一个两者都不是的答案?

标签: c# max min lis


【解决方案1】:

你已经接近了,你只需要添加一个过滤器来找到匹配的项目:

var max =  minMaxList.Max(r => r.getMax())

var itemsWithMax = minMaxList.Where(r => r.getMax() == max);

Min 也是如此。

我想知道是否可以在单个命令中完成

可能会使用复杂的分组或连接,但我会先得到一些有效的东西,然后尝试使其更好(记住单个查询并不总是“比多个查询更好)。

【讨论】:

  • 不太可能是最有效的方式,具体取决于高效的预期含义。
  • @Jodrell 很公平 - 删除了评论。
【解决方案2】:

您始终可以过滤可枚举,而不是只让最大值通过:

var maxvalue = minMaxList.Max(w => w.getMax());
var maxitems = minmaxlist.Where(w => w.getMax() == maxvalue);

【讨论】:

  • 不太可能是最有效的方式,具体取决于高效的预期含义。
  • 学术。通过列表进行两次 O(n) 扫描的替代方法是一次扫描 O(n) 并将该最大值的“重复”插入列表(另一个 O(n))。无论哪种方式都给您相同的 O(2n)(与 O(n) 相同),而另一种方式也以 O(n) 的速率消耗内存。
  • 基本上,它的效率较低,但不是指数级的。实际上,您是对的,尤其是对于 3 个列表。但是,OP 确实要求“最有效”,...
  • 为了它的价值,我减少了答案的内存分配。
  • 是吗?您正在使用随机读取的 五个 数组,而不是一个顺序读取的单个数组,这很可能适合您的 L1/L2 缓存。
【解决方案3】:

尝试分组:

    var grpWithMaxVaues = minMaxList.GroupBy(c => c.getMax())
                                    .OrderByDescending(c => c.Key)
                                    .FirstOrDefault() 

        var max =   grpWithMaxVaues.FirstOrDefault();

Console.WriteLine(max.FileName);

【讨论】:

    【解决方案4】:

    给你,像这样。

    允许您在列表的一个枚举中找到最小值和最大值,这可能比多次枚举列表更快,就像在其他答案中一样。

    这是working demonstration

    我对使用单元素数组来存储值并不完全满意,但它们使种子的值类型属性可变。这避免了不断重新分配聚合的需要。

    var minMaxInfo = minMaxList.Skip(1)
        .Aggregate(
            new
            { 
                Max = new int[] { minMaxList[0].Max },
                MaxIndexes = new List<int> { 0 },
                Min = new int[] { minMaxList[0].Min },
                MinIndexes = new List<int> { 0 },
                Index = new int[] { 0 }
            },
            (r, t) =>
            {
                r.Index[0]++;       
                if (t.Min < r.Min[0])
                {
                    r.Min[0] = t.Min;
                    r.MinIndexes.Clear();
                    r.MinIndexes.Add(r.Index[0]);
                } 
                else if (t.Min == r.Min[0])
                {
                    r.MinIndexes.Add(r.Index[0]);   
                }
    
                if (t.Max > r.Max[0])
                {
                    r.Max[0] = t.Max;
                    r.MaxIndexes.Clear();
                    r.MaxIndexes.Add(r.Index[0]);
                }
                else if (t.Max == r.Max[0])
                {
                   r.MaxIndexes.Add(r.Index[0]);
                }
    
                return r;
            });
    

    允许,

    Console.WriteLine("MaxValue: {0}", minMaxInfo.Max[0]);
    Console.WriteLine(
        "MaxFiles: {0}",
        string.Join(
            ", ",
            minMaxInfo.MaxIndexes.Select(i => minMaxList[i].FileName)));
    Console.WriteLine("MinValue: {0}", minMaxInfo.Min[0]);
    Console.WriteLine(
        "MinFiles: {0}",
        string.Join(
            ", ",
            minMaxInfo.MinIndexes.Select(i => minMaxList[i].FileName)));
    

    【讨论】:

      【解决方案5】:

      你问的是解决这个问题的最有效方法。

      确定最大值/最小值并在之后搜索这些项目需要迭代列表两次。我会在一个循环中手动解决它

      List<Entry> ResultList = new List<Entry>();
      ResultList.Add(minMaxList[0]);
      foreach (Entry item in minMaxList)
      {
          if (item.getMax() >= ResultList[0].getMax())
          {
              if (item.getMax() != ResultList[0].getMax())
              {
                  ResultList.Clear();
              }
              ResultList.Add(item);
          }
      }
      

      【讨论】:

        【解决方案6】:

        我发现这是最短的方法。

        var newList = new List<Hero>();
        var maxValue = newList.OrderByDescending(x => x.Level).ToList()[0];
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-02-17
          • 1970-01-01
          • 2017-09-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-06-29
          • 2022-10-19
          相关资源
          最近更新 更多