我正在嘗試從字典中獲取前n個值。對我來說并不容易的部分是,如果有多個相同等級的值,我需要保留所有這些值。例如,如果字典如下所示:
Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add("AAA", 91);
dict.Add("BBB", 97);
dict.Add("CCC", 98);
dict.Add("DDD", 92);
dict.Add("EEE", 97);
dict.Add("FFF", 100);
如果我想要前 3 名,我需要得到
dict.Add("BBB", 97);
dict.Add("CCC", 98);
dict.Add("EEE", 97);
dict.Add("FFF", 100);
因為 BBB 和 EEE 具有相同的等級。我首先按排名對字典進行排序,并嘗試過,Take()但只使用了兩者中的一個。
/* Does not work */
var dictSorted = dict.OrderByDescending(x => x.Value).ToDictionary(x => x.Key, x => x.Value).Take(3);
/* The below only prints
FFF = 100
CCC = 98
BBB = 97
but not
EEE = 97
*/
foreach(KeyValuePair kvp in dictSorted){
Console.WriteLine(kvp.Key " = " kvp.Value);
}
有沒有好的方法來實作這一目標?
uj5u.com熱心網友回復:
您可以使用grouping withGroupBy方法將具有不同Key但相同Values 的專案包含到結果中:
var kvpGroups = dict.OrderByDescending(x => x.Value).GroupBy(x => x.Value).Take(3);
在這里,你走不前3個KeyValuePairS,你先服用3組的KeyValuePair秒。KeyValuePair如果每個組Value在源集合中是唯一的,則每個組可能包含一個,或者KeyValuePair如果其中一些具有相同Value的s,則可能包含多個s。
您可以使用foreach下一種方式(kvpmeans KeyValuePair)迭代組:
foreach (var kvpGroup in kvpGroups)
{
foreach (var kvp in kvpGroup)
{
Console.WriteLine(kvp.Key " = " kvp.Value);
}
}
// Output:
// FFF = 100
// CCC = 98
// BBB = 97
// EEE = 97
或 LINQ 版本:
foreach (var kvp in from kvpGroup in (from kvp in dict
orderby kvp.Value descending
group kvp by kvp.Value into kvpGroup
select kvpGroup).Take(3)
from kvp in kvpGroup
select kvp)
{
Console.WriteLine(kvp.Key " = " kvp.Value);
}
uj5u.com熱心網友回復:
您還沒有完全清楚要求,但我假設您打算采用常見模式,即在沒有搶七局的情況下得分,前 N 名有資格,如果第 N 名并列,那么所有并列的人也有資格. 例如,如果您有 [10, 10, 9, 9, 8, 8] ,那么前 3 名將是 [10, 10, 9, 9],因為您有兩個第一名、兩個第三名和兩個第五名。第 3 名及以上的每個人都有資格。但是如果你有 [10, 10, 10, 9, 9, 9] 那么只有 10s 會通過,因為你有三個第一名和三個第四名——第四名沒有晉級。
可能有一種更優雅的方法來做到這一點,但最直接的方法是取第一個 n,然后加上所有與您最后一個系結的那些。
using System;
using System.Collections.Generic;
using System.Linq;
public static class Extension
{
public static IEnumerable<TSource> TopNWithTies<TSource, TKey>(this IEnumerable<TSource> sequence, Func<TSource, TKey> keySelector, int n) {
var sequenceDescending = sequence.OrderByDescending(keySelector);
var topN = sequenceDescending.Take(n);
TKey cutoff = keySelector(topN.Last());
var ties = sequenceDescending.Skip(n).TakeWhile(item => keySelector(item).Equals(cutoff));
return topN.Concat(ties);
}
}
public class Program
{
public static void Main()
{
Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add("AAA", 91);
dict.Add("BBB", 97);
dict.Add("CCC", 98);
dict.Add("DDD", 92);
dict.Add("EEE", 97);
dict.Add("FFF", 100);
var top3 = dict.TopNWithTies(kvp=>kvp.Value, 3);
foreach(var kvp in top3){
Console.WriteLine(kvp.Key " = " kvp.Value);
}
}
}
相反,如果您想計算每個專案的排名,您可以執行類似的操作,將 0 索引排名應用于所有分數。基本上每個分數的排名都等于超過它的其他分數的數量。
using System;
using System.Collections.Generic;
using System.Linq;
public static class Extension
{
public static IEnumerable<(TSource item, int rank)> RankDescending<TSource, TKey>(this IEnumerable<TSource> sequence, Func<TSource, TKey> keySelector) {
int rank = 0;
foreach (var group in sequence.OrderByDescending(keySelector).GroupBy(keySelector))
{
foreach (var item in group)
{
yield return (item, rank);
}
rank = group.Count();
}
}
}
public class Program
{
public static void Main()
{
Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add("AAA", 91);
dict.Add("BBB", 97);
dict.Add("CCC", 98);
dict.Add("DDD", 92);
dict.Add("EEE", 97);
dict.Add("FFF", 100);
var top3 = dict.Rank(kvp=>kvp.Value).TakeWhile(item => item.rank<3);
foreach(var (item, rank) in top3){
Console.WriteLine(item.Key " = " item.Value " at rank #" rank);
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/316001.html
