【问题标题】:How to sort a lookup?如何对查找进行排序?
【发布时间】:2011-10-29 22:56:46
【问题描述】:

您好,我有一个存储字符串和整数的查找类型。

static Lookup<string, int> lookup;
lookup = (Lookup<string, int>)list.ToLookup(i => i.IP, i => i.Number);

但现在我需要按值(数字)对该查找进行排序,并获取前 10 个键及其值。

这怎么可能?

【问题讨论】:

  • 我试图理解这一点。为什么要将i.Number 转换为string
  • 您好,抱歉,它应该是 int。我现在就改,晚上回家试试也记下答案。非常感谢大家。

标签: linq sorting lookup


【解决方案1】:

很遗憾,Lookup 中的元素无法重新排序。

但是 ToLookup() 方法有一个很好的属性,即所有分组中的元素与原始序列中的元素具有相同的顺序。

这意味着通过一些 Linq 体操,你可以通过使用 GroupBy 来实现你想要的:

var l = (from l in list
         // group elements by key
         group l by l.IP into g
         // for each group order the elements and take top 10
         select new { g.Key, Items = g.OrderBy(g1 => g1.Number).Take(10)} into g2
         // flaten group into an enumerable using select many
         from g in g2.Items
         select g)
         // get the desired lookup containing the top 10 ordered elements for each key
        .ToLookup(g => g.IP, g => g.Number);

【讨论】:

  • 哦,他想要前十名而不是前十名?我完全错过了。
  • "所有分组中的元素与原始序列中的元素具有相同的顺序" - 很高兴知道。
【解决方案2】:

我不确定您为什么要将 Lookup&lt;string, int&gt; 转换为 Lookup&lt;string, string&gt;,但您想要的一般答案是:

var list = new List<Test>
    {
            new Test { IP = "A", Number = 1 }, new Test { IP = "A", Number = 3 }, new Test { IP = "A", Number = 4 },
            new Test { IP = "B", Number = 1 }, new Test { IP = "B", Number = 1 }, new Test { IP = "B", Number = 1 },
            new Test { IP = "C", Number = 1 },
            new Test { IP = "D", Number = 1 },
            new Test { IP = "E", Number = 1 }, new Test { IP = "E", Number = 1 }, new Test { IP = "E", Number = 1 }
    };

var values = list.ToLookup(s => s.IP, s => s.Number)
                 .OrderByDescending(s => s.Count())
                 .Take(10);

【讨论】:

  • 警告此代码,以防万一“列表”是一组实体的数据库,调用类似于ToList()ToLookup() 不会返回 IQueryable,因此它会将所有查询数据带入内存.具有数百万条记录的表性能不佳。
  • 否则您将如何进行查找?
【解决方案3】:

去找一个优先队列(你可以在http://www.itu.dk/research/c5/找到一个)。遍历您的查找并将从查找中的每个条目创建的 IComparable 项插入优先级队列。从优先级队列中选择前十项。或者只是按计数作为键对它们进行排序。

var lookup = list.ToLookup( l => l.IP, l => l.Number );
var topten = lookup.OrderByDescending( l => l.Count() )
                   .Take( 10 );

foreach (var item in topten)
{
    Console.WriteLine( "{0}: {1}", item.Key, item.Count() );
}

请注意,排序最多具有 O(nlogn) 性能,而良好的基于​​堆的优先级队列将具有 O(logn) 性能。如果集合不大,排序会更简单,因为内置支持它并且不需要中间类来支持优先级队列实现。

【讨论】:

  • 您好,您的答案是正确的,但是我无法将两个答案标记为正确。非常感谢您的帮助。
【解决方案4】:

看看Take() LINQ 函数,您应该能够执行Take(10) 之类的操作,只返回10 个结果。至于排序,请查看接受 lambda 表达式作为排序机制的 OrderBy() 函数。将它们结合起来应该可以满足您的需求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-09
    • 2022-01-27
    • 2016-08-24
    • 2015-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多