【问题标题】:How to the get an object based on 2 criteria without doing extensive searching?如何在不进行广泛搜索的情况下根据 2 个标准获取对象?
【发布时间】:2011-10-23 06:55:37
【问题描述】:

很难将其概括为 1 行问题。我有这样的课:

class Item
{
    int Count {get; set;}
    double Value {get; set;}
}

还有一个 List<Item> 包含任意数量的 Item 值。

如何获得Item 最低Count 和最高Value

性能并不重要,但优雅才是最重要的,因为我不希望有巨大的嵌套循环来执行此操作,除非没有优雅的方式,即 Linq 等。

编辑:

这是一个示例列表,其中可能包含这些Items

{Count, Value}

{2, 10}, {6, 60}, {5, 21}, {4, 65}, {2, 35}, {4, 18}, {3, 55}, {7, 99}, {2, 25}

所以这里我想要的值是{2, 35},因为它在所有项目中具有最低的Count,而对于具有相同Count 值的项目,它具有最高的Value

【问题讨论】:

  • 您想要返回两个项目,一个具有最低的计数和一个具有最高值的项目,或者您只希望返回一个项目,其中 Count 是最低的并且来自该项目的值最高?
  • 这是两个独立的查询吗?此外,它必须是List<T>,还是您愿意维护一个专门构建的数据结构,以便按需高效地执行所需的查询?
  • @BigL:对不起,我的意思是单个项目的Count 最低,但Value 最高。
  • @Joan:如果计数最低的项目不是价值最高的项目怎么办?还是这是一个多目标优化?
  • @Ani:我使用List<T>,但我不确定你的意思。你的意思是像 IEnumerable 这样的东西?我猜这可能无关紧要。

标签: c# .net linq collections


【解决方案1】:

好的,现在我们有点清楚了:

只要 Count 最低,该范围内的最高 Value 即可

这很容易......

var best = list.OrderBy(x => x.Count)
               .ThenByDescending(x => x.Value)
               .FirstOrDefault();

如果列表为空,则为null,否则为计数最低的项目,如果有多个具有该计数的项目,则为具有最高值的项目。

这比它可能的效率要低,因为我们可以真的通过创建一个比较器来比较任何两个值来一次完成 - 但这肯定是正确的方法代码最少的元素。

【讨论】:

  • 谢谢乔恩,这正是我想要的。比较器是指在Item 类中?
  • @JoanVenge:要么让Item 实现IComparer / IComparer<T>,要么提供一个单独的IComparer<Item> 传递给MaxMin 方法。
  • 谢谢乔恩,顺便说一句,如果我有IComparer<T>,我是否可以使用Min,并获得相同的结果?只是好奇。
【解决方案2】:

希望它现在可以使用,遗憾的是不像 Jon 那样优雅

var res = (from i in items
           orderby i.Count ascending, i.Value descending
           select i).FirstOrDefault();

【讨论】:

  • 这不起作用。你明白为什么吗?将您的答案与乔恩的仔细进行比较。
【解决方案3】:

使用morelinq(具有MinByMaxBy 运算符),您可以在线性时间内轻松完成此操作(不幸的是需要额外的通过):

IEnumerable<item> items = ...

var minCount = items.Min(item => item.Count);
var minCountItemWithMaxValue = items.Where(item => item.Count == minCount)
                                    .MaxBy(item => item.Value);

使用适当的 AllMinBy 扩展,返回 所有 序列中的最小项目(遗憾的是在 morelinq 中丢失),您可以提高效率:

var minCountItemWithMaxValue = items.AllMinBy(item => item.Count)
                                    .MaxBy(item => item.Value);

编辑

这是一种(丑陋的)方法,可以在 O(1) 空间和 O(n) 时间内使用标准 LINQ 一次性完成:

var minCountItemWithMaxValue = items.Aggregate(
                                (bestSoFar, next) =>
                                (next.Count < bestSoFar.Count) ? next :  
                                (next.Count > bestSoFar.Count) ? bestSoFar :
                                (next.Value > bestSoFar.Value) ? next : bestSoFar);

【讨论】:

  • 我们真的需要一个带有链式比较的MaxBy...但这很难表达。将不得不考虑它......(我确实考虑过提到MoreLINQ,但觉得在这种情况下不值得。)
  • @Jon: AllMinByAllMaxBy 会相对容易,是吗?
  • 这并不理想,因为您必须保留当前具有最小值的所有项目的列表等。保留 O(1) 内存方面会很好.我确信使用其他界面是可行的,但是否值得努力是另一回事。
  • @Jon:顺便说一句,“MoreLINQ”而不是“morelinq”是您首选的大写形式吗?我使用“morelinq”是因为它是在项目页面上大写的。
  • @Jon: 当然可以,但是因为它们是不同的扩展名(没有必要去掉O(1) 空格MinByMaxBy),客户必须明确要求它占用了O(n) 空间。
猜你喜欢
  • 2013-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多