I want to get the keys of the highest values in a dictionary
{'a' : 1, 'b' : 2, 'c' : 2}
. In this case I want it to return 'b'
but use of
weight.Aggregate((l, r) => l.Value > r.Value ? l : r).Key;
returns the last largest value i.e. 'c'
.
- Is there a way to return the key of the first largest value in my dictionary? =>
'b'
- Also, is it possible to return an array of keys of the max tied values? =>
new char[]{'b', 'c'}
- Which Key-Value data structure should I use instead?
EDIT: Since it has caused quite a stir in the comments, I mean the first largest value in terms of insertion order.
CodePudding user response:
(For the sake of suggesting something)
Inspired by this answer, I am going to suggest an approach where you create your own type that inherits from List<KeyValuePair<char, int>>
(thereby preserving insertion order), and hides the base.Add()
method using a method that ensures that only entries with unique key
s are added to your list.
This works nicely for your specific use case if you can add your items one by one, and if adding items to your list is the only way you intend to change your list content. If there is a chance you may need to e.g. remove items from your list, the implementation needs to be extended to cover that.
Also worth mentioning: This implementation lets an incident of trying to add an entry with a non-unique key to the list pass silently. There's no screaming; the entry is simply not added.
Implementation:
public class UniqueKeyKvpList : List<KeyValuePair<char, int>>
{
private readonly HashSet<char> _keys = new HashSet<char>();
// Hiding base method List<KeyValuePair<char, int>>.Add()
public new void Add(KeyValuePair<char, int> kvp) => Add(kvp.Key, kvp.Value);
// Simpler .Add() method; imitates Dictionary.Add() in usage
public void Add(char key, int value) => AddIfUniqueKey(key, value);
private void AddIfUniqueKey(char key, int value)
{
if (!_keys.Contains(key))
{
_keys.Add(key);
base.Add(new KeyValuePair<char, int>(key, value));
}
}
}
Usage:
var myKvpList = new UniqueKeyKvpList();
myKvpList.Add('a', 1);
myKvpList.Add('a', 2); // will not be added (duplicate key)
myKvpList.Add('b', 3);
After populating the list, you can get all chars with the max value as follows:
.Net 6 (due to use of .MaxBy()
)
char[] charsWithMaxValue = myKvpList
.GroupBy(kvp => kvp.Value)
.MaxBy(gr => gr.Key) // Group key is the kvp value
.Select(kvp => kvp.Key)
.ToArray();
< .Net 6
char[] charsWithMaxValue = myKvpList
.GroupBy(kvp => kvp.Value)
.OrderByDescending(gr => gr.Key) // Group key is the kvp value
.First()
.Select(kvp => kvp.Key)
.ToArray();
The first char with the max value will then be
char firstCharWithMaxValue = charsWithMaxValue.First();
Alternatively, if computing charsWithMaxValue
is not needed for anything, firstCharWithMaxValue
can be calculated directly as follows:
.Net 6
char firstCharWithMaxValue = myKvpList
.MaxBy(kvp => kvp.Value)
.Key;
< .Net 6
char firstCharWithMaxValue = myKvpList
.OrderByDescending(kvp => kvp.Value)
.First()
.Key;
Example fiddle here.