c# - How to iterate through a dictionary and compare values? - c#

I'm teaching myself c# and working on my own mini project. The program populates an array with random numbers, the program returns the number (0-15) and the number of occurrences it appears in the array. I stored these values in a dictionary as I wanted to sort the values without losing the key mapped to it.
The sorted values are then stored into another dictionary and now I want to be able to iterate through the dictionary and get the key with the highest value. In other words print to the console the number with the most occurrences. As the dictionary is sorted, the last number will be the highest value.
However there could be more than one number tied for the most occurrences and that's where I'm stuck on. If the numbers 4,5,6,7 all appear the most number of times, i want to be able to print that to the console.
Dictionary<int, int> dic = new Dictionary<int, int>();
//iterates through numbers 0-15
for (int y = 0; y <= 15; y++)
{
int m = 0;
//iterates through entire array
for (int i = 0; i < Arr.Length; i++)
{
//comparisons
if (y == Arr[i])
{
m++;
}
}
//Inserts number and count into the dictionary
dic.Add(y,m);
}
//Sorts the dictionary and adds the sorted one into a new dictionary
Dictionary<int, int> dic2 = new Dictionary<int, int>();
foreach (KeyValuePair<int, int> value in dic.OrderBy(key => key.Value))
{
Console.WriteLine("{0} appears {1} times ", value.Key, value.Value);
dic2.Add(value.Key, value.Value);
}
//Finds the keys with most common occurance
KeyValuePair<int, int> e = dic2.Last();
foreach (KeyValuePair<int, int> comp in dic2)
{
if (dic.Last() == dic[comp])
{
//something goes here
Console.WriteLine("Most common number is {0}", e.Key);
}
}
I'm not sure whether to use indexes to compare using the key or if there is another way to do this like I have tried above, using a foreach loop

I wouldn't use the current approach at all, to be honest - you're doing much more work than you need to. LINQ gives you much better tools than this. You can use GroupBy to make it all cleaner:
var pairs = array.GroupBy(x => x)
.Select(g => new { Key = g.Key, Count = g.Count() }
.OrderByDescending(pair => pair.Count)
.ToList();
That gets you all the key/count pairs, most-frequent first. The display part should then be reasonably simple, e.g.
// Note: this relies on the initial array being non-empty
var highestCount = pairs.First().Count;
foreach (var pair in pairs.TakeWhile(pair => pair.Count == highestCount))
{
Console.WriteLine("{0}: {1}", pair.Key, pair.Count);
}
Just to be clear, the code above replaces all the code in your question. You don't need a Dictionary<,> at all.

You could use a linq query to find the number of ocurrencies for each key and count it. After, return a anon object with the Key and total, for sample:
var q = from k in dic
let t = dic.Count(x => x.Value == k.Key)
select new { Key = k.Key, Total = t };
var max = q.OrderByDescending(x => Total).First();
Console.WriteLine("Most common number is {0} with {1} ocurrencies", max.Key, max.Total);

Related

Retrieve value from a sorted dictionary with the help of ke in C#

I have a Dictionary, which has a hash table, that is, keys are not sorted.
Conflicts oConflicts = oClash.Conflicts;
Dictionary<string, string> dConflicts = new Dictionary<string, string>();
Conflict oConflict;
for (int iLoopC = 1; iLoopC <= oConflicts.Count; iLoopC++)
{
oConflict = oConflicts.Item(iLoopC);
if (Math.Abs(oConflict.Value) < 3)
{
dConflicts.Add(oConflict.Value.ToString(), oConflict.SecondProduct.ToString());
}
}
I have sorted the dictionary by LINQ:
var sortedDict = dConflicts.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
I am new to this. Could someone help me with how to get the value stored in sortedDict using the particular key value? Like the last value using count the array elements.
This seems that you are only using a Dictionary just to be sure not Adding duplicates, pretty overkill, but hey...
var searchedLastElement = dConflicts.OrderBy(x => x.Value).LastOrDefault().Value;
yod didn't need the sorted list to be cast again to dictionary only to retrieve the last element

Partition Keys in List<KeyValuePair> c#

I have a List of KeyValuePairs
var hitCoord = new List<KeyValuePair<int, double>>()
and sorted like this (descending by Key)
hitCoord.Sort((a, b) => (b.Key.CompareTo(a.Key)));
I can find the total highest Value with
hitCoord.Sort((a, b) => (b.Value.CompareTo(a.Value)));
(^ maybe that can be used for the following query?)
I would like to partition the Keys in my list such that I can find Values that meet a condition within the specified range of keys.
i.e. I would like to find the highest Value and Lowest Value in a range of (int)Keys
for (i=0; i<hitCoord.Count; i++)
{
if (hitCoord[i].Key > (int lowerbound) && hitCoord[i].Key < (int upperBound)
{
find highest Value?
}
}
Not sure if that is at all on the right track. I am new to programming and very new to KeyValuePairs. Any help you can offer on this matter is much appreciated! Thank you!
Finding the max value in a specified range of keys could be solved by using LINQ (using System.Linq;) like this:
hitCoord.Where(c => c.Key > lowerbound && c.Key < upperbound).Max(c => c.Value);
The approach:
Use Where to filter all items with key in range
Use Max to get the max value
You could adapt and extend the query also with more checks and constraints. Some basic queries are described in Basic LINQ Query Operations (C#).
You don't need to actually sort - you can do this with Linq (adding using System.Linq; to the top of your .cs file). You just want a Where to filter by key and a Max to get the highest value:
var maxValue = hitCoord.Where(hc => hc.Key > lowerbound && hc.Key < upperBound)
.Max(hc => hc.Value);
As others have suggested this is all pretty easy to do with linq. here's another sample of linq calls including how to create a partition lookup.
var hitCoord = new List<KeyValuePair<int, double>>()
{
new KeyValuePair<int, double>(1, 1.1),
new KeyValuePair<int, double>(1, 1.2),
new KeyValuePair<int, double>(2, 2.0),
new KeyValuePair<int, double>(2, 2.1)
};
var partitions = hitCoord.ToLookup(kvp => kvp.Key % 2);
var maxKvp = hitCoord.Max(kvp => kvp.Key);
var minKvp = hitCoord.Min(kvp => kvp.Key);
int lower = 1;
int higher = 2;
var maxInRange = hitCoord.Where(kvp => kvp.Key >= lower && kvp.Key <= higher).Max(kvp => kvp.Key);
That said if this is perfromance critical then you'll probably want to use something other than linq so you can optimize it and avoid going through the list multiple times.

How do I match/search for a specific dictionary key?

very new to c#.
I'm working with an API that returns a dictionary with 2 keys and 1 value.
This is my current code:
var dic = API.getVehicleValidMods((VehicleHash)sender.vehicle.model);
foreach (KeyValuePair<int, Dictionary<int, string>> kvp in dic)
{
Dictionary<int, string> kvp2 = kvp.Value;
foreach (KeyValuePair<int, string> kvp3 in kvp2)
{
API.consoleOutput("Key = {0}, Key = {1}, Value = {2}", kvp.Key, kvp3.Key, kvp3.Value);
Here is a sample from the result it returns:
As you can see the first keys are sometimes the same number and they sometimes skip numbers.
I'm trying to return all matching "key number 2" that matches a certain "key 1".
The string values are not of importance in my case, I'm only interested in the ints.
So, my pseudo logic tells me something like
"foreach keynumber2 in keynumber1 (the integer, eg. 23) do this:"
should work, however I'm unsure how to code it properly.
tl;dr How do i find all "key2" that matches a certain "key1" ?
So, you want to find all inner keys of specific outer key. You can do this with this line of code:
var key1 = 42;
var allKeys = dic.ContainsKey(key1)
? dic[key1].Keys.ToArray()
: new int[0];
If outer dictionary contains 42 as a key this will return all inner keys. Otherwise it will return an empty ints array.
var matchesFrom1 = from val in dic where val.Key == 1 select val.Value;
var valueList = from val in matchesFrom1 where val.Key == 2 select val.Value;
valueList is the string of values returned
You could use LINQ methods:
Use .Where method to filter your initial collection of KeyValuePairs<> by key.
Use SelectMany to flatten resulting IEnumerable<KeyValuePair<int, Dictionary<>>> to a simple IEnumerable<int>
Use Distinct to make sure there are no duplicate keys (or omit this part if it is not necessary).
var someKey = 16;
var result = dic
.Where(x => x.Key == someKey)
.SelectMany(kv => kv.Value.Keys)
.Distinct()
.ToArray();

C# iterate keys in reverse order

I have a dictionary that has int keys. The keys are in random order and are not necesserily consequtive (e.g. 5, 3, 11, 12, 10, 4). I would like to visit each key-value pair in reverse order of key size. So for the example above I'd like to visit (12,11,10...).
The way I see how to do this is to get a count of the number of elements, find the max key by say binary search and then find the next largest value that is smaller than the current max etc. untill I've processed the number of elements contained in the dictionary.
However, there could be a method already existing. For a discussion on how to find the max key: Get the largest key in a dictionary
var pairs = dictionary.OrderByDescending(pair => pair.Key);
foreach(var pair in pairs)
{
var value = pair.Value;
...
}
foreach (var p in myDict.OrderByDescending(pair => pair.Key)) {
// process pair
}
Well, it's easy enough to retrieve all of the keys from a dictionary, you can then use the LINQ OrderByDescending() operator to get them in reverse order:
foreach( var key in yourDictionary.Keys.OrderByDescending(x => x) )
{
// your logic here
}
If you need the value associated with the key, you can also do:
foreach( var keyValuePair in yourDictionary.OrderByDescending(kvp => kvp.Key) )
{
// your logic here
}
You can, of course, use query comprehension syntax is LINQ as well:
var yourResult = from kvp in dictionary
order by kvp.Key descending
select YourProjectionFunction(kvp);
dic = dic.OrderByDescending(p=>p.Key).ToDictionary(p => p.Key, p => p.Value);

Use List<T>ForEach to add element to HashTable

I have a list of string values that I want add to a hashtable or other array that can be accessed by key/index but cannot implement it. I have this working how I want but its ugly
List<string> valueList = new List<string>();
valueList.Add("1");
valueList.Add("2");
valueList.Add("3");
Hashtable p = new Hashtable();
valueList.ForEach(delegate(string f) { p.Add(valueList.FindIndex(v => v == f), f); });
EDIT: After James reminded me that a List will return values by index I went with a List and this is what I have ended up with
valueList.ForEach(f => sequenceList.Add(int.Parse(f)));
Even if it compiled, it wouldn't work - calling GetEnumerator().Current will always fail because it'll give you a new iterator positioned before the first item.
What do you want the key for each item to be? If it's just its position within the list, I don't see the benefit that gives you over a list (which is already indexed by int). However, you can do it like this (assuming that valueList is a List<string>:
var dictionary = valueList.Select((item, index) => new { item, index })
.ToDictionary(x => x.index, x => x.item);
Adding it to an existing dictionary, I'd just do:
for (int i=0; i < valueList.Count; i++)
{
dictionary[i] = valueList[i];
}
Not everything has to be done with lambdas :)
Note that this won't have quite the same effect as using FindIndex if you have repeated values.
Try this:
valueList.ForEach(x => htable.Add(valueList.FindIndex(y => y == x), x));
Although, there's really no reason not to use a for here
for (var index = 0; index < valueList.Count; index++)
{
htable.Add(index, valueList[index]);
}
It's more lines of code, but it's more straightforward and will perform much better (findIndex is far less efficient than using the index from the for statement).
Assuming you want the strings to be the keys and the index to be the value:
Hashtable ht = new Hashtable();
for (var i = 0; i <= valueList.Count; i++)
{
ht.Add(valueList[i], i);
}
Otherwise switch the ht.Add parameters around. However, if that is the case you would be best just to leave it as a List < string >.
List<string> list = new List<string>{"w", "y", "u", "i", "n"};
HashSet<string> hset = new HashSet<string>(list);
Using ForEach for this is not efficient, as you have to use FindIndex to find out where you are. It works, but you will do a lot of extra work:
valueList.ForEach(x => htable.Add(valueList.FindIndex(y => y == x), x));
It's better to just use a regular loop, so that you get the index without having to seek through the table:
for (int i = 0; i < valueList.Count; i++) {
htable.Add(i, valueList[i]);
}

Categories

Resources