Export dictionary to a JSON, sorted by keys - c#

I have a dictionary
Dictionary<string, object>
(the values are either string, int or double).
I export the dictionary to a JSON file:
JsonConvert.SerializeObject(myDict);
I want the saved JSON to be sorted by keys.

If you use a SortedDictionary<TKey, TValue>, it'll be serialized in order of the keys:
var dict = new SortedDictionary<string, int>
{
{ "Z", 3 },
{ "B", 2 },
{ "A", 1 },
};
var json = JsonConvert.SerializeObject(dict);
Console.WriteLine(json);
Output:
{"A":1,"B":2,"Z":3}

You could use SortedDictionary
https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.sorteddictionary-2?view=netframework-4.7.2
It sorts your entries by key so you don't need to perform any sorting on your own.

Just use temporary SortedDictionary object:
var unsortedDic = new Dictionary<string, int>
{
{"Z", 3},
{"B", 2},
{"A", 1},
};
var sortedJson = JsonConvert.SerializeObject(new SortedDictionary<string, int>(unsortedDic));
Output:
{"A":1,"B":2,"Z":3}

You can sort your dictionary like this:
JsonConvert.SerializeObject(myDict.OrderBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value));

Related

How can I replicate this code by using anonymous function (lambda)?

I have a nested dictionary which looks like this:
Dictionary<string, Dictionary<string, int>> users = new Dictionary<string, Dictionary<string, int>>();
The first string is the name of the user, the second is the contest he is taking part in and the int is his score. One user can take part in multiple contests.
My task is to find the user with the highest score by adding all the points he has. For now I used this code :
foreach (var user in users)
{
bestUsers.Add(user.Key, 0);
foreach (var contest in user.Value)
{
bestUsers[user.Key] += contest.Value;
}
}
I want to know how to do it by using anonymous function looking something like this :
KeyValuePair<string, int> bestUser = users.OrderBy(x => x.Value.Sum());
Instead of a nested dictionary, you can create a class that represents the results of the User:
public class UserGameResults
{
public string Name { get; set; } // the name of the user
public int TotalScore { get => GameResults.Select(x => x.Value).Sum(); } // total score of all games, will be calculated every time the property is accessed
public Dictionary<string,int> GameResults { get; set; } = new Dictionary<string,int>(); // key is the name of the game, value is the score
}
If you use a Dictionary<string,UserGameResults>, you will get your result more easily:
var bestResult = users.OrderByDescending(x => x.Value.TotalScore).FirstOrDefault();
Moreover, a Dictionary<string,UserGameResults>tells you much more about the meaning of the data than the Dictionary<string,Dictionary<string,int>>.
try this
var dict = new Dictionary<string, Dictionary<string, int>> {
{ "name1", new Dictionary<string, int>{ { "A", 2 }, {"B", 3 }}},
{ "name2", new Dictionary<string, int>{ { "C", 4 }, {"D", 5 }}}
};
var scores = dict.Select(d => new { name = d.Key, score = d.Value.Select(x => x.Value).Sum() } )
.ToList().OrderByDescending (d =>d.score );
scores
name2 9
name1 5
You use Dictionary<TKey,TValue> when you need to store values with some unique keys associated to them, and accessing them by that key is convenient for you.
I don't know why you use dictionary here. Your user name must not be unique I think. So if user name is not unique then how can u store all user in a dictionary. I think you should use list instead of Dictionary.
Dictionary<string, Dictionary<string, int>> users = new Dictionary<string, Dictionary<string, int>>()
{
{ "A", new Dictionary<string, int>(){
{"sub1", 10},
{"sub2", 20},
{"sub3", 30}
}
},
{ "B", new Dictionary<string, int>(){
{"sub1", 10},
{"sub2", 40},
{"sub3", 30}
}
}
};
var result = users.OrderBy(x => x.Key).ToDictionary(m => m.Key, m => m.Value.Sum(k => k.Value));
Dictionary is pretty fast, well optimized and offer the performance you need in most cases. But in most of the cases it doesn't really matter, the performance of a chained list of key-value pairs would have also been enough.
For the code refactor to use linq to get the dictionary instead of the 2 foreach loops, you could use something like this:
users.ToDictionary(u => u.Key, u => u.Value.Select(c => c.Value).Sum());
OR I think Sum took an selector lambda
users.ToDictionary(u => u.Key, u => u.Value.Sum(c => c.Value));
Should be valid

Find value in Dictionary<int,List<int>>

I have a dictionary with int key and List value
I would like to find out if the key or values contains a specific integer and get the related key for it.
Example:
Dictionary<int, List<int>> removableStuff = new Dictionary<int, List<int>>();
removableStuff.Add(1, new List<int> {1});
removableStuff.Add(3, new List<int> {9,33,35});
removableStuff.Add(2, new List<int> {1,65,32,3});
I would like to find the number 3.
Since the number 3 can be found as key and value, the output would be: 3, 2.
This should yield the desired result:
var num = 3;
var keys = removableStuff.Where(i => i.Key.Equals(num) || i.Value.Any(num.Equals))
.Select(i => i.Key);
You can optionally call .ToList() after the .Select(), if you don't want to deal with an Enumerable.
The i.Value.Any(num.Equals) can also be simplified to i.Value.Contains(num), but when I use Linq I like to use Any for that sort of stuff too. (Just personal preference)
Nonetheless this is very basic Linq and I'm sure you would've found your answer prior to asking, if you would've looked.
A similar method to Tobias' answer is to use Contains instead of Any(Equals):
Dictionary<int, List<int>> removableStuff = new Dictionary<int, List<int>>
{
{1, new List<int> {1}},
{3, new List<int> {9, 33, 35}},
{2, new List<int> {1, 65, 32, 3}}
};
int find = 3;
var matches = removableStuff.Where(item => item.Key == find || item.Value.Contains(find));
foreach (var match in matches)
{
Console.WriteLine($"{match.Key}: {string.Join(", ", match.Value)}");
}

need get unique set of keys from Multiple dictionaries<Datetime,double>

I have 20 dictionaries of <Datetime,double> that are mostly for the same range of dates (e.g. feb 24-2012 through june 4 2012). Some dictionaries have extra days, and some are missing days. I want an array of all the unique dates being used.
Currently I'm iterating through all the keys and adding to a hashset to get a unique set, then converting the hashset to an array. Is there a more efficient way?
For the record I also considered iterating through and using the containsKey function of the dictionary and add to a list, or LINQ. My existing process seems to do the trick.
The code you described is the most efficient you can get.
You can do it with less code (and similar efficency) with LINQ:
dicts.SelectMany(d => d.Keys).Distinct().ToArray();
you can pull all the dictionaries into list that allow "duplicates in keys" and then use the Distinct function:
Dictionary<DateTime, double> dic = new Dictionary<DateTime, double>()
{
{DateTime.Now, 111}
};
Dictionary<DateTime, double> dic2 = new Dictionary<DateTime, double>()
{
{DateTime.Now, 111}
};
var list = dic.ToList();
list.AddRange(dic2.ToList());
var final = list.Distinct().ToDictionary(x => x.Key, x => x.Value);
I found this post while looking for a solution to a slightly different problem but used the accepted answer as the basis for my solution, so I thought someone with the same problem might come down this path too.
I was looking for a way to find a single property in a group of objects that was unique across the property set for each object. I have the property names in dictionaries and I wanted a list of keys that only appear in one dictionary.
Here's my solution, which you should just be able to paste into linqpad to see it working.
void Main()
{
var d = new Dictionary<string, Dictionary<string, string>>
{
{
"First",
new Dictionary<string, string>
{
{"A", "ash"},
{"B", "brett"},
{"R", "ripley"},
{"J", "jones"},
{"D", "dallas"}
}
},
{
"Second",
new Dictionary<string, string>
{
{"A", "ash"},
{"B", "brett"},
{"R", "ripley"},
{"D", "dallas"},
{"K", "kane"}
}
},
{
"Third",
new Dictionary<string, string>
{
{"A", "ash"},
{"B", "brett"},
{"R", "ripley"},
{"D", "dallas"},
{"V", "vasquez"}
}
},
{
"Fourth",
new Dictionary<string, string>
{
{"A", "ash"},
{"B", "brett"},
{"R", "ripley"},
{"D", "dallas"},
{"H", "hicks"}
}
}
};
var u = d.Values.SelectMany(x => x.Keys).Distinct().Where(y => d.Values.SelectMany(z => z.Keys).Count(a => a == y) == 1).ToArray();
foreach (var f in u)
{
Console.WriteLine("{0} => {1}", f, d.Keys.Single(s => ((Dictionary<string, string>)d[s]).ContainsKey(f)));
}
}

LINQ ToDictionary how to get item index?

I've a Dictionary, which I want to convert to another Dictionary, using the rule implied by below sample:
Inputs:
Dictionary<string, string> inputs = new Dictionary<string, string>(3)
{
{ "A", "First" },
{ "Z", "Third" },
{ "J", "Second" }
};
Output:
Dictionary<int, string> output = new Dictionary<string, string>(3)
{
{ 0, "First" },
{ 1, "Second" },
{ 2, "Third" }
};
Can I do it using lambda syntax & no intermediary objects?
Thanks.
The order of enumeration of a dictionary is indeterminate (i.e. items don't have an index), so I'm not sure that this is possible. How would the integer values be derived?
EDIT:
I get it now:
inputs
.OrderBy(input => input.Key)
.Select((input, index) => new {index, input.Value})
.ToDictionary(x => x.index, x => x.Value)
If you can define what the ordering should be, then I would do it like this (I chose to order by key):
Dictionary<string, string> inputs = new Dictionary<string, string>(3)
{
{ "A", "First" },
{ "Z", "Third" },
{ "J", "Second" }
};
var outputs = inputs.OrderBy(i=>i.Key).Select(i=>i.Value).ToArray();
// output
// String [] (3 items):
First
Second
Third
This gives you an array with the indices that you asked for (e.g. output[0]).
If you really want dictionary entries back, you can get an ienumerable of them like this (you can't just return a dictionary because they're unordered):
var outputs = inputs.OrderBy(i=>i.Key).Select(
(entry, index) => new KeyValuePair<int, string>(index, entry.Value));
Throw a .ToArray() on there if you need to.
If you really want a dictionary back, try this:
var outputs = inputs.OrderBy(i=>i.Key)
.Select((entry, i) => new { entry.Value, i })
.ToDictionary(pair=>pair.i, pair=>pair.Value).Dump();
Just keep in mind that dictionaries are not inherently ordered so if you enumerate over it, you should add a .OrderBy again.

Reversing Dictionary using LINQ in C#

How to convert
Dictioanry<String,List<String>> into Dictionary<String,String>
i'm having a dictionary like
Dictioanry<String,List<String>>dictOne=new Dictionary<String,List<String>>();
and which containg
Key(String) Value(List<String>)
A a1,a2
B b1,b2
C c1
i need to convert the "dictOne" into
Dictionary<String,String> dictReverse=new Dictionary<String,String>()
So the result will be like
Key(String) Value(String)
a1 A
a2 A
b1 B
b2 B
c1 C
is there any way to do this using LINQ
Thanks in advance
Update: As others have noted, in order for a dictionary to be truly "reversible" in this way, the values in your List<string> objects need to all be unique; otherwise, you cannot create a Dictionary<string, string> with an entry for every value in your source dictionary, as there would be duplicate keys.
Example:
var dictOne = new Dictionary<string, List<string>>
{
{ "A", new List<string> { "a1", "a2" } },
{ "B", new List<string> { "b1", "b2" } },
{ "C", new List<string> { "c1", "a2" } } // duplicate!
};
You have (at least) two options for dealing with this.
Option 1: Throw on duplicates
You may want to ensure that every element in every List<string> is, in fact, unique. In this case, a simple SelectMany with a ToDictionary will accomplish what you need; the ToDictionary call will throw an ArgumentException on encountering a duplicate value:
var dictTwo = dictOne
.SelectMany(kvp => kvp.Value.Select(s => new { Key = s, Value = kvp.Key }))
.ToDictionary(x => x.Key, x => x.Value);
The most generic way (that comes to mind) to abstract this functionality into its own method would be to implement an extension method that does this for any IDictionary<T, TEnumerable> implementation where TEnumerable implements IEnumerable<TValue>:
// Code uglified to fit within horizonal scroll area
public static Dictionary<T2, T1> ReverseDictionary<T1, T2, TEnumerable>(
this IDictionary<T1, TEnumerable> source) where TEnumerable : IEnumerable<T2>
{
return source
.SelectMany(e => e.Value.Select(s => new { Key = s, Value = e.Key }))
.ToDictionary(x => x.Key, x => x.Value);
}
The ugly proliferation of generic type parameters in the above method is to allow for types other than strictly Dictionary<T, List<T>>: it could accept a Dictionary<int, string[]>, for example, or a SortedList<string, Queue<DateTime>> -- just a couple of arbitrary examples to demonstrate its flexibility.
(A test program illustrating this method is at the bottom of this answer.)
Option 2: Skip duplicates
If duplicate elements in your List<string> values is a realistic scenario that you want to be able to handle without throwing an exception, I suggest you take a look at Gabe's excellent answer for an approach that uses GroupBy (actually, Gabe also provides a flexible approach that can cover either of these two cases based on a selector function; however, if you definitely want to throw on a duplicate, I'd still suggest the above approach, as it should be somewhat cheaper than using GroupBy).
Example program
Here's a little test program illustrating Option 1 above on a Dictionary<string, List<string>> with no duplicate elements in its List<string> values:
var dictOne = new Dictionary<string, List<string>>
{
{ "A", new List<string> { "a1", "a2" } },
{ "B", new List<string> { "b1", "b2" } },
{ "C", new List<string> { "c1" } }
};
// Using ReverseDictionary implementation described above:
var dictTwo = dictOne.ReverseDictionary<string, string, List<string>>();
foreach (var entry in dictTwo)
{
Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
}
Output:
a1: A
a2: A
b1: B
b2: B
c1: C
// Associates each key with each of its values. Produces a sequence like:
// {A, a1}, {A, a2}, {B, b1}, {B, b2}, {C, c1}
var kvps = from kvp in dictOne
from value in kvp.Value
select new { Key = kvp.Key, Value = value };
// Turns the sequence into a dictionary, with the old 'Value' as the new 'Key'
var dictReverse = kvps.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
Of course, each key in the original dictionary must be associated with a unique set of values, and no key must be associated with values that are also associated with other keys.
Also bear in mind that Dictionary<K, V> does not define any sort of enumeration order. You can use the Enumerable.OrderBy method to enumerate the resulting dictionary in the appropriate order.
In the event that you would end up with duplicate keys in your result dictionary, you would have to pick a single one of those keys. Here's an implementation that just picks the first one it sees (using First):
var dictReverse = (from kvp in dictOne
from value in kvp.Value
group kvp.Key by value)
.ToDictionary(grp => grp.Key, grp => grp.First());
Given this input dictionary:
var dictOne = new Dictionary<string, IEnumerable<string>> {
{ "C", new List<string> { "c1", "a2" } },
{ "B", new List<string> { "b1", "b2" } },
{ "A", new List<string> { "a1", "a2" } } };
The result would be:
c1: C
a2: C
b1: B
b2: B
a1: A
As Dan points out, you may want different behavior in the case of duplicate keys. You can create this function:
public static Dictionary<V, K> Transpose<K, V>(
this Dictionary<K, IEnumerable<V>> dictOne,
Func<IEnumerable<K>, K> selector)
{
return (from kvp in dictOne
from V value in kvp.Value
group kvp.Key by value)
.ToDictionary(grp => grp.Key, grp => selector(grp));
}
Then you could call it like dictOne.Transpose(Enumerable.First) to get the above behavior, dictOne.Transpose(Enumerable.Single) to get an exception when there's a duplicate key (the behavior of other posts), dictOne.Transpose(Enumerable.Min) to pick the first one lexicographically, or pass in your own function do whatever you need.

Categories