简体   繁体   English

如何在C#中对字典列表进行排序和“裁剪”

[英]How to sort & “crop” a dictionary list in C#

I wanna use only top N list items and delete the rest. 我想只使用前N个列表项并删除其余项。 I thought I duplicated & sorted matches as _listTopN but when I clear matches it also clears _listTopN 我以为我复制并排序匹配_listTopN但是当我清除匹配时它也清除了_listTopN

In short, how can I get the max 3 list items in an unordered dictionary list and put them back that same dictionary? 简而言之,如何在无序字典列表中获取最多3个列表项并将它们放回同一个字典?

Dictionary<int, float> matches;

... ...

if (matches.Count > Settings.requiredMatch)
{
   var _listTopN = matches.OrderByDescending(s => s.Value).Take(Settings.requiredMatch);

   matches.Clear();

   foreach (var p in _listTopN)
      matches.Add(p.Key, p.Value);

}

Linq queries are evaluated lazily. Linq查询被懒惰地评估。 Your statement where you assign _listTopN doesn't perform any work, it only prepares the query ; 您分配_listTopN语句不执行任何工作,它只准备查询; this query will only be executed when you start enumerating the results. 只有在开始枚举结果时才会执行此查询。 Since you clear matches before you start enumerating the query, there is nothing in the source to enumerate... 由于在开始枚举查询之前清除了matches ,因此源中没有任何内容可以枚举...

If you want the query to be evaluated eagerly, add ToList at the end: 如果您希望急切地评估查询,请在结尾处添加ToList

var _listTopN = matches.OrderByDescending(s => s.Value)
                       .Take(Settings.requiredMatch)
                       .ToList();

Alternatively, you can use ToDictionary to perform all the work in a single query: 或者,您可以使用ToDictionary在单个查询中执行所有工作:

matches = matches.OrderBy(s => s.Value)
                 .Take(Settings.requiredMatch)
                 .ToDictionary(s => s.Key, s => s.Value);

Force it to evaluate earlier: 强制它先评估:

var _listTopN = matches.OrderByDescending(s => s.Value)
    .Take(Settings.requiredMatch).ToList();

LINQ has deferred execution (as part of composition); LINQ延迟执行(作为组成的一部分); in most cases, nothing is actually evaluated until you foreach over the data. 在大多数情况下,没有什么实际评估 ,直到你foreach过来的数据。 The ToList() makes this happen earlier, ie before you clear the dictionary. ToList()使得这种情况更早发生,即在清除字典之前。

You can assign the result to matches with ToDictionary : 您可以将结果分配ToDictionary matches

if (matches.Count > Settings.requiredMatch)
{
    matches = matches
        .OrderByDescending(s => s.Value)
        .Take(Settings.requiredMatch)
        .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}

That is because _listTopN is holding on to a deferred query, lazily executed when you loop on it. 这是因为_listTopN持有一个延迟查询,当你循环它时懒惰地执行。

In other words, var _listTopN = ... does not evaluate the query, it returns a recipe for how to evaluate it when needed. 换句话说, var _listTopN = ...不会对查询进行求值,它会返回一个如何在需要时对其进行求值的方法。

Since you clear the underlying source before you evaluate it, it'll "change", that is, return something other than what you wanted/expected. 由于您在评估它之前清除了基础源,它将“改变”,即返回除您想要/期望之外的其他内容。

The simple fix is to force evaluation, so do this: 简单的解决方法是强制评估,所以这样做:

var _listTopN = matches.OrderByDescending(s => s.Value)
    .Take(Settings.requiredMatch).ToArray();
                                 ^--------^  <-- add this

This evaluates your query and stores the result as an array that won't change, and now you can safely clear your underlying data source. 这将评估您的查询并将结果存储为不会更改的数组,现在您可以安全地清除基础数据源。

Your LINQ expression _listTopN is lazily evaluated which means that it doesn't evaluate its result until your foreach statement. 您的LINQ表达式_listTopN被延迟评估,这意味着它不会在您的foreach语句之前评估其结果。 But at this point you have already cleared matches source, so you get nothing in _listTopN also. 但是此时你已经清除了matches源,所以你也没有在_listTopN得到任何东西。 You can force LINQ methods to evaluate their results by calling ToArray for example. 例如,您可以通过调用ToArray强制LINQ方法来评估其结果。

 var _listTopN = matches.OrderByDescending(s => s.Value).Take(Settings.requiredMatch)
                          .ToArray(); 

See this statement in MSDN 请参阅MSDN中的此语句

This method is implemented by using deferred execution 此方法通过使用延迟执行来实现

if (matches.Count > Settings.requiredMatch)
  matches = matches.OrderByDescending(s => s.Value)
  .Take(Settings.requiredMatch)
  .ToDictionary(s => s.Key, s => s.Value);

Gets matches into the state you want simply and clearly. 简单明了地获得您想要的状态matches

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM