Order two dictionaries based on the keys - c#

I've got two dictionaries with the same keys.
The first one contains the count to a specific key and the second one is like a lookup, it contains the real "values" to the specific key.
Here is an example:
1. dict:
Key: Value:
0; 10
1; 17
2; 3
3; 28
4; 8
2. dict:
Key: Value:
0; String1
1; String2
2; String3
3; String4
4; String5
Now I need to order these dictionaries by the value of the 1. dictionary. I know how to order just the first one but i don't have an idea how to do it for the second dictionary.
The expected output is:
1. dict:
Key: Value:
0; 28
1; 17
2; 10
3; 8
4; 3
2. dict:
Key: Value:
0; String4
1; String2
2; String1
3; String5
4; String3

Well, dictionaries (like these)
var dict1 = new Dictionary<int, int>() {
{0, 10},
{1, 17},
{2, 3},
{3, 28},
{4, 8},
};
var dict2 = new Dictionary<int, string>() {
{0, "String 1"},
{1, "String 2"},
{2, "String 3"},
{3, "String 4"},
{4, "String 5"},
};
doesn't have any order. However, we can represent (with a help of Linq) data sorted:
// Just an OrderBy...
var result1 = dict1
.OrderByDescending(pair => pair.Value);
// It may appear, that dict1 doesn't have corresponding value
// that's why we have to introduce "found" variable
var result2 = dict2
.Select(pair => {
bool found = dict1.TryGetValue(pair.Key, out var value);
return new {
pair,
found,
value
};
})
.OrderByDescending(item => item.found)
.ThenByDescending(item => item.value)
.Select(item => item.pair);
Console.WriteLine(string.Join(Environment.NewLine, result1);
Console.WriteLine();
Console.WriteLine(string.Join(Environment.NewLine, result2);
Outcome:
[3, 28]
[1, 17]
[0, 10]
[4, 8]
[2, 3]
[3, String 4]
[1, String 2]
[0, String 1]
[4, String 5]
[2, String 3]
In case you want to enumerate Values only (without Keys) we can add one more Select:
.Select((pair, i) => $"{i + 1}; {pair.Value}");
Like this:
var result1 = dict1
.OrderByDescending(pair => pair.Value)
.Select((pair, i) => $"{i + 1}; {pair.Value}");
var result2 = dict2
.Select(pair => {
bool found = dict1.TryGetValue(pair.Key, out var value);
return new {
pair,
found,
value
};
})
.OrderByDescending(item => item.found)
.ThenByDescending(item => item.value)
.Select(item => item.pair)
.Select((pair, i) => $"{i + 1}; {pair.Value}");
Outcome:
1; 28
2; 17
3; 10
4; 8
5; 3
1; String 4
2; String 2
3; String 1
4; String 5
5; String 3

If key would be same for both the dictionary with same sequence then this would be the design.
Combine two dictionary into one and order them and then generate the sequence number on that.
var dict1 = new Dictionary<int, String>();
dict1.Add(10, "string1");
dict1.Add(17, "string2");
dict1.Add(3, "string3");
dict1.Add(28, "string4");
dict1.Add(8, "string5");
var dict2 = new Dictionary<int, String>();
int i = 0;
foreach (KeyValuePair<int, string> author in dict1.OrderByDescending(key => key.Key))
{
dict2.Add(i, author.Value);
i++;
}
foreach (KeyValuePair<int, string> author in dict2)
{
Console.WriteLine("Key: {0}, Value: {1}", author.Key, author.Value);
}
DEMO

Related

Adding Array elements based on other array

I have two arrays whose elements are one to one mapped.
string [] denom = new string[] { EUR, GBP, EUR, USD, USD};
int [] count = new int[] { 1, 3, 4, 7, 8};
EUR - 1
GBP - 3
EUR - 4
USD - 7
USD - 8
I want to get an output into an array by summing the count based on the denom
So, EUR - 5 (1 +4), GBP - 3, USD - 15 (7+8)
The output array should have values like {5, 3 , 15}
We have a logic to remap the final count with Denoms (i.e, EUR, GBP, USD)
We want the logic in C#.net
To achieve desired output below code sample will help you.
string[] denom = new string[] { "EUR", "GBP", "EUR", "USD", "USD" };
int[] count = new int[] { 1, 3, 4, 7, 8 };
//Create dictionary object to manage group by denom
Dictionary<string, int> dct = new Dictionary<string, int>();
//Iterate and sum group by denom
for (int i = 0; i < denom.Length; i++)
{
if (!dct.Keys.Contains(denom[i]))
dct[denom[i]] = 0;
dct[denom[i]] += count[i];
}
//Print output
foreach (KeyValuePair<string, int> kpVal in dct)
Console.WriteLine(kpVal.Key + "=" + kpVal.Value);
dct.Clear();
See the output printed below.
You could simply create a map and keep up the sum as below:
Map<String, Integer> currencyValueMap = new HashMap<>();
for (int i=0; i<denom.length; i++) {
currencyValueMap.put(denom[i], (k, v) v == null ? count[i] : count[i] + v);
}
At the end, you would be left with currency name as key while total value as a value against that particular key.

C# - How to find the most common and the least common integers in an array?

I was asked to make a Dice program with two arrays (one for each dice) and add the two results, e.g.: 2 (dice 1) + 6 (dice 2) = 8.
The program must roll the dices 100 times and show the sum each time.
I could do it so far, but the program also must show which sum is the most frequent, and which sum is the least frequent.
Like this: sum = [2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6]. Most common: 2; Least common: 5.
How can I do it?
This is how my code looks like:
static void Main(string[] args)
{
Random gerador = new Random();
int[] soma = new int[100];
int rolagem = 0;
for(int i = 0; i < soma.Length; i++)
{
rolagem = 0;
rolagem += gerador.Next(6) + 1;
rolagem += gerador.Next(6) + 1;
soma[i] = rolagem;
}
var mais = soma.GroupBy(item => item).OrderByDescending(g => g.Count()).Select(g => g.Key).First();
//NEED TO FIND OUT LEAST COMMON SUM
for (int j = 1; j < soma.Length; j++)
{
Console.Write("{0} ", soma[j]);
}
Console.WriteLine("Soma mais frequente: {0}, Soma menos frequente: {1}", mais, menos);
Console.ReadKey();
}
You're almost there, you can find the least common one similarly:
var array = new[] { 1, 1, 1, 1, 4, 2, 2, 3, 3, 3, 5, 5 };
var result = array.GroupBy(i => i).OrderBy(g => g.Count()).Select(g => g.Key).ToList();
var mostCommon = result.Last();
var leastCommon = result.First();
If you have code that rolls the dice 100 times, you are pretty close. All you need to do is frequency counters.
A roll of a pair of dice yields a number between 2 and 12, inclusive. Make an int count[13] array before entering the loop.
In the loop each time you have two numbers, say, d1 and d2, increment the count as follows:
count[d1+d2]++;
Once the loop is over, find the highest and the lowest numbers in the array between indexes 2 and 12, inclusive. The index of the highest number will be the number with the highest roll count; the index of the lowest number will be the number with the lowest roll count.
Tuple<int, int> least = new Tuple<int, int>(-1, -1), most = new Tuple<int, int>(-1, -1);
List<int> arr = new List<int> { 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6 };
var grp = arr.GroupBy(x => x).Select(x=>x).ToList();
foreach (var item in grp)
{
if (least.Item2 == -1 || least.Item2>item.Count())
{
var x = new Tuple<int, int>(item.Key, item.Count());
least = x;
}
if (most.Item2 == -1 || most.Item2 < item.Count())
{
var x = new Tuple<int, int>(item.Key, item.Count());
most = x;
}
}
Console.WriteLine("Least : "+least.Item1+" repeated " + least.Item2+"times");
Console.WriteLine("Most : "+most.Item1 + " repeated " + most.Item2 + "times");
Or as m1kael suggested,
Tuple<int, int> least = new Tuple<int, int>(-1, -1), most = new Tuple<int, int>(-1, -1);
List<int> arr = new List<int> { 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6 };
var grp = arr.GroupBy(x => x).OrderBy(x=>x.Count()).Select(x => x.Key).ToList();
Console.WriteLine("Least : "+ grp.First());
Console.WriteLine("Most : "+ grp.Last());
There is a small chance for more than one most or least common:
var a = Enumerable.Repeat(new Random(), 100).Select(r => r.Next(6) + r.Next(6) + 2);
var groups = a.GroupBy(i => i).GroupBy(g => g.Count(), g => g.Key).OrderBy(g => g.Key).ToList();
var mostCommon = string.Join(", ", groups.Last());
var leastCommon = string.Join(", ", groups[0]);

Convert Jagged Array to IEnumerable<KeyValuePair<int,int>>?

I have this Jagged Array :
(n is given at compile time , so please assume that all values are already there)
int[][] jagged = new int[n][];
jagged[0] = new int[3];
jagged[0][0] = 2; // Please ignore the dummy values....
jagged[0][1] = 55;
jagged[0][2] = 4;
jagged[1] = new int[3];
jagged[1][0] = 6;
jagged[1][1] = 3;
jagged[1][2] = 7;
...
...
jagged[n] = new int[3];
jagged[n][0] = 9;
jagged[n][1] = 5;
jagged[n][2] = 1;
I want to create a IEnumerable<KeyValuePair<int,int>> from this structure where :
key is : dummy value and the value is the n ( dummy value is unique)
(aside info - I need to map pictures to users)
So for group #1 I want:
{2-> 0}
{55-> 0}
{4-> 0}
for group #2
{6 -> 1}
{3-> 1}
{7-> 1}
...
...
etc
But as a whole list :
So final result should be 1 IEnumerable of KeyValuePair<int,int>:
{2-> 0}
{55-> 0}
{4-> 0}
{6 -> 1}
{3-> 1}
{7-> 1}
...
{9 -> n}
{5-> n}
{1-> n}
Question :
Is there any Linq'y way of doing it ?(instead of loops over loops ) ?
foreach (var t in jagged.SelectMany((row, rowIndex) => row.Select(value => new KeyValuePair<int, int>(value, rowIndex))))
{
Console.WriteLine("{0} - {1}", t.Key, t.Value);
}

How to consolidate a Dictionary with multiple (three) keys by reducing one or more key and merging the multiple records (if any) into one single one?

I have a Dictionary with the following definition.
Dictionary<int[], int> D = new Dictionary<int[], int>();
where the key is a 3 element array. I am giving this as example to simplify my scenario. (In my own code the Key is a complex class object that has a List of 3-7 elements in it for key.)
int[] key;
key = new int[] { 1, 1, 1 };
D.Add(key, 1);
key = new int[] { 1, 1, 2 };
D.Add(key, 2);
key = new int[] { 1, 1, 3 };
D.Add(key, 3);
key = new int[] { 1, 2, 4 };
D.Add(key, 4);
key = new int[] { 2, 1, 1 };
D.Add(key, 5);
key = new int[] { 2, 5, 1 };
D.Add(key, 6);
What i want is to have a means to reduce the number of keys, ie. instead of having an array of three element I want a 2 element array as key and have all the values that are redundant be consolidated into one single value so that the resulting KeyValue pairs should look the following way. (reducing the first index for keys)
{1 1, 6} //two instances of matching key of {1 1} resulted the value to have 1+5 =6
{1 2, 2}
{1 3, 3}
{2 4, 4}
{5 1, 6}
First of all, your dictionary probably doesn't work as you expect - there is no default comparer for int[] type, so keys won't be unique in your dictionary (you can have two elements with 1 1 1 key for example). To get this to work you need to provide custom IEqualityComparer<int[]>. This will also be needed to make the solution to your main problem work:
public class IntArrayEqualityComparer : IEqualityComparer<int[]>
{
public bool Equals(int[] x, int[] y)
{
if (x.Length != y.Length)
{
return false;
}
return x.Zip(y, (v1, v2) => v1 == v2).All(b => b);
}
public int GetHashCode(int[] x)
{
return 0;
}
}
So you should create your dictionary as follows:
Dictionary<int[], int> D
= new Dictionary<int[], int>(new IntArrayEqualityComparer());
Returning to the main issue, here is how you can achieve the desired result:
var result = D
.GroupBy(
kvp => kvp.Key.Skip(1).ToArray(),
new IntArrayEqualityComparer())
.ToDictionary(
g => g.Key,
g => g.Sum(x => x.Value));

Dictionary ++ not working as expected

Let's say we have a dictionary like this:
var dic = new Dictionary<Int32, Int32>();
Whereas the key is the ID and the value is the count.
Now we want to add a new key. This works perfectly fine with the following line:
dic[1] = 1; //adding ID 1, Count 1 to the current Dictionary
Assuming we have a list of integer with the following values:
var ids = new List<int> {1, 2, 3 , 1, 2};
Where we would like to get a dictionary with the following content:
[1, 2] ==> (ID 1, Count 2)
[2, 2] ==> (ID 2, Count 2)
[3, 1] ==> (ID 3, Count 1)
The obvious solution would be:
foreach (var id in ids)
{
dic[id]++;
}
But this is throwing a KeyNotFoundException. So obviously the operator += is not supported for dictionaries.
I already attached an answer to this problem.
Is there any better way of how to achieve this?
You can use LINQ for simpler:
var dic = ids.GroupBy(id => id)
.ToDictionary(g => g.Key, g => g.Count());
My solution:
var dic = new Dictionary<Int32, Int32>();
var ids = new List<int> { 1, 2, 3, 1, 2 };
foreach (var id in ids)
{
if (dic.ContainsKey(id))
{
dic[id]++;
} else {
dic[id] = 1;
}
}

Categories

Resources