How to iterate in reverse through an OrderedDictionary - c#

How can I iterate through an OrderedDictionary in reverse and access its keys?
Since it doesn't have any support for LINQ extensions, I have tried the following:
var orderedDictionary= new OrderedDictionary();
orderedDictionary.Add("something", someObject);
orderedDictionary.Add("another", anotherObject);
for (var dictIndex = orderedDictionary.Count - 1; dictIndex != 0; dictIndex--)
{
// It gives me the value, but how do I get the key?
// E.g., "something" and "another".
var key = orderedDictionary[dictIndex];
}

May I suggest to use SortedDictionary<K, V>? It does support LINQ and it is type safe:
var orderedDictionary = new SortedDictionary<string, string>();
orderedDictionary.Add("something", "a");
orderedDictionary.Add("another", "b");
foreach (KeyValuePair<string, string> kvp in orderedDictionary.Reverse())
{
}
Also, as Ivan Stoev pointed out in a comment, the returned items of the OrderedDictionary aren't ordered at all, so SortedDictionary is what you want.

You can lessen the complexity of this problem significantly by using a regular Dictionary (or SortedDictionary, depending on your requirements) and keep a secondary List to keep track of the keys' insertion order. You can even use a class to facilitate this organization:
public class DictionaryList<TKey, TValue>
{
private Dictionary<TKey, TValue> _dict;
private List<TKey> _list;
public TValue this[TKey key]
{
get { return _dict[key]; }
set { _dict[key] = value; }
}
public DictionaryList()
{
_dict = new Dictionary<TKey, TValue>();
_list = new List<TKey>();
}
public void Add(TKey key, TValue value)
{
_dict.Add(key, value);
_list.Add(key);
}
public IEnumerable<TValue> GetValuesReverse()
{
for (int i = _list.Count - 1; i >= 0; i--)
yield return _dict[_list[i]];
}
}
(And of course add whatever other methods you need as well.)

Since it doesn't have any support for LINQ extensions...
That's because it's a non-generic Enumerable. You can make it generic by casting it to the right type:
foreach (var entry in orderedDictionary.Cast<DictionaryEntry>().Reverse()) {
var key = entry.Key;
var value = entry.Value;
}

You can get an element at an index like this:
orderedDictionary.Cast<DictionaryEntry>().ElementAt(dictIndex);
And for getting the Key:
orderedDictionary.Cast<DictionaryEntry>().ElementAt(dictIndex).K‌​ey.ToString();

I am not bothered with the order fact. You can get the key by copying the keys to an indexable collection. Also the condition of the loop needed to be changed to dictIndex > -1;.
Please try this:
var orderedDictionary = new OrderedDictionary();
orderedDictionary.Add("something", someObject);
orderedDictionary.Add("another", anotherObject);
object[] keys = new object[orderedDictionary.Keys.Count];
orderedDictionary.Keys.CopyTo(keys, 0);
for (var dictIndex = orderedDictionary.Count-1; dictIndex > -1; dictIndex--)
{
// It gives me the value, but how do I get the key?
// E.g., "something" and "another".
var key = orderedDictionary[dictIndex];
// Get your key, e.g. "something" and "another"
var key = keys[dictIndex];
}

If you need to use an OrderdDictionary, you can always use a SortedDictionary like below.
var orderedDictionary = new SortedDictionary<int, string>();
orderedDictionary.Add(1, "Abacas");
orderedDictionary.Add(2, "Lion");
orderedDictionary.Add(3, "Zebera");
var reverseList = orderedDictionary.ToList().OrderByDescending(pair => pair.Value);
foreach (var item in reverseList)
{
Debug.Print(item.Value);
}

Related

How can I merge two dictionaries without getting ArgumentException on the key?

I can't figure out how to keep the keys and values on a dictionary when I try to merge two dictionaries. I keep getting ArgumentException due to duplicate of key. When the key match I would just like to add the value by =+ kvp.value;
I have a list of Dictionaries where the
1st Dictionary = kvp = "jump", 2;
2ndDictionary = kvp = "jump", 4;
I like to merge them and get something like:
Dictionary = kvp = "jump", 6;
That I can later add to my list of Dictionaries
I've tried to run something I found in StackOverflow thread.
foreach (var dict in listOfDict)
{
dict.SelectMany(d => d)
.ToLookup(pair => pair.Key, pair => pair.Value)
.ToDictionary(group => group.Key, group => group.First());
}
But I keep getting.
cannot be inferred from the usage. Try specifying the type arguments
explicitly.
I want to avoid getting all keys and all values on separate lists that I later loop through to add key and value on a new dictionary.
Simplest extension to list of dictionary of double values with using Linq:
public static class ExtListOfDict {
public static Dictionary<TKey, double> SumValue1<TKey>(this List<Dictionary<TKey, double>> list)
=> list?.SelectMany(i => i).ToLookup(i => i.Key, i => i.Value).ToDictionary(i => i.Key, i => i.Sum());
}
without linq:
public static Dictionary<TKey, double> SumValue2<TKey>(this List<Dictionary<TKey, double>> list) {
if(list?.Count > 0) {
var dir = new Dictionary<TKey, double>(list[0]);
for(var i = 1; i < list.Count; i++)
foreach (var kv in list[i])
if (dir.TryGetValue(kv.Key, out double sum))
dir[kv.Key] = sum + kv.Value;
else
dir.Add(kv.Key, kv.Value);
return dir;
} else
return null;
}
If you like the LINQ approach, I would go with something like this:
var dictionaries = new List<Dictionary<string, int>>(); // this is the list of dictionaries you want to merge
var unifiedDictionary = new Dictionary<string, int>(); // this is the dictionary where you merge and add the values
foreach (var kvp in dictionaries.SelectMany(dictionary => dictionary))
{
if (unifiedDictionary.ContainsKey(kvp.Key))
{
unifiedDictionary[kvp.Key] += kvp.Value;
}
else
{
unifiedDictionary.Add(kvp.Key, kvp.Value);
}
}
However, if this is too hard to read (I am not always a fan of excessive LINQ over explicit code blocks), you can use the for-loop approach:
var dictionaries = new List<Dictionary<string, int>>(); // this is the list of dictionaries you want to merge
var unifiedDictionary = new Dictionary<string, int>(); // this is the dictionary where you merge and add the values
foreach (var dictionary in dictionaries)
{
foreach (var kvp in dictionary)
{
if (unifiedDictionary.ContainsKey(kvp.Key))
{
unifiedDictionary[kvp.Key] += kvp.Value;
}
else
{
unifiedDictionary.Add(kvp.Key, kvp.Value);
}
}
}
Hope this helps you. If further help and explanations are needed, please tell me.
Here is a solution based on the CollectionsMarshal.GetValueRefOrAddDefault API (.NET 6), and on the INumber<TSelf> interface (.NET 7):
public static Dictionary<TKey, TValue> ToSumDictionary<TKey, TValue>(
this IEnumerable<Dictionary<TKey, TValue>> dictionaries)
where TValue : struct, INumber<TValue>
{
ArgumentNullException.ThrowIfNull(dictionaries);
Dictionary<TKey, TValue> result = null;
foreach (var dictionary in dictionaries)
{
if (result is null)
{
result = new(dictionary, dictionary.Comparer);
continue;
}
if (!ReferenceEquals(dictionary.Comparer, result.Comparer))
throw new InvalidOperationException("Incompatible comparers.");
foreach (var (key, value) in dictionary)
{
ref TValue refValue = ref CollectionsMarshal
.GetValueRefOrAddDefault(result, key, out bool exists);
refValue = exists ? refValue + value : value;
}
}
result ??= new();
return result;
}
The key of each KeyValuePair<TKey, TValue> in each dictionary is hashed only once.
If you are getting an exception due to duplicate keys, then it sounds like you have duplicate keys!
Have you checked the two dictionaries before you try to merge them? Simply calling =+ kvp.value without checking to see if the first dictionary already has a key of that name is very likely to be your problem.
You need to check for an existing entry with that key, and if one is found, take whatever action is appropriate for your scenario (ie ignore, overwrite, ask the user to decide, etc)

C# Populate dynamically nested Dictionary with unknown depth

I get an array of Nodes and a Value into my Method which have to be nested into a Dictionary Structure. But I really need help with the logic here.
I did a static Test which shows what I need:
public static Dictionary<string, object> CreateNestedDictionary(string[] chainNodes, string value)
{
// Testvalues:
// ["application", "deepNode", "evenDeeperNode"], "Value"
var container = new Dictionary<string, object>();
container.Add("application", new Dictionary<string, object>() { { "deepNode", new Dictionary<string, string>(){{"evenDeeperNode", "Value" } }}});
return container;
}
So basically, I have a Dictionary<string, object> variable, which can contain an infinite number of Dictionaries of the same type. At the very end, I need a Dictionary<string, string> to define the last node and the value.
By Node I mean the Key of the Dictionary. Those will later be represented in a JSON Sctructure.
The thing is, that I don't know how many Elements I get in chainNodes. Also, I may have to call this Method several times and add more Nodes. I would then have several chainNodes which have to go into the same Dictionary structure. Iwould then have to make sure that the Keys stay unique.
Is there any easy way to populate this structure dynamically? Or even a LINQ approach that deals with this?
Any advice is much appreciated. Thank you in advance
Update
After the comments I realized I did a really bad job explaining this.
Here is another example:
public static Dictionary<string, object> CreateNestedDictionary(string[] chainNodes, string value)
{
// Testvalues:
// ["application", "deepNode", "evenDeeperNode"], "Value"
var container = new Dictionary<string, object>();
for (int i = 0; i < chainNodes.Length; i++)
{
if (i != chainNodes.Length -1)
{
container.Add(chainNodes[i], new Dictionary<string, object>()); // fill this empty Dictionary
}
else
{
container.Add(chainNodes[i], value);
}
}
}
Adding the last Dictionary is easy but I don't know how to fill the Dictionaries after the first.
If I have understood this correctly: chainNodes is a list of the names, and value goes in the deepest dictionary (with name chainNodes[chainNodes.Length-1]).
Summary: you need to iterate and special case the deepest node.
Something recursive is probably easiest, starting with the pure creation case (no need to check for existing entries).
public Dictionary<string, object> CreateNestedDictionary(string[] chainNodes, object value) {
return DoCreate(chainNodes, value, 0);
}
private Dictionary<string, object> DoCreate(string[] chainNodes, object value, int index) {
var res = new Dictionary<string, object>();
if (index == chainNodes.Length - 1) {
// Bottom out the recursion
res.Add(chainNodes[index], value);
} else {
res.Add(chainNodes[index], DoCreate(chainNodes, value, index+1));
}
return res;
}
Recursion naturally allows you to special case that last string because that is the end case that recursion must have.
For the adding to an existing collection case, you need to change the recursion to:
Pass down the current node
Check if chainNodes[index] key exists and use that entry or create a new one.
Here's how I implemented infinite nesting Dictionaries.
My structure is: Dict([bool],object), ending with [bool] = true.
public void Init(bool[] boolArray)
{
BoolDict = new Dictionary<bool, object>();
Dictionary<bool, object> parent = BoolDict;
for (int index = 0; index < boolArray.Length; index++)
{
if (index < boolArray.Length - 1)
{
Dictionary<bool, object> nestedDict = new Dictionary<bool, object>();
parent.Add(boolArray[index], nestedDict);
parent = nestedDict;
}
else
{
parent.Add(boolArray[index], true);
}
}
}
It's important to save the new Dict as the parent so that you can add to the new parent which you created in the previous iteration.
You could remove the first value from the chainNodes and recursively call the method if there are any more values until you reach the end.
I'm with #Blorgbeard, though in that, this is a poor structure.
public static Dictionary<string, object> CreateNestedDictionary(string[] chainNodes, string value)
{
// Testvalues:
// ["application", "deepNode", "evenDeeperNode"], "Value"
var key = chainNodes.First();
chainNodes = chainNodes.Skip(1).ToArray();
return new Dictionary<string, object> { { key, chainNodes.Any() ? CreateNestedDictionary(chainNodes, value) : value } };
}

Generic List Contains() perfomance and alternatives

I need to store big amount of key, value pairs where key is not unique. Both key and value are strings. And items count is about 5 million.
My goal is to hold only unique pairs.
I've tried to use List<KeyValuePair<string, string>>, but the Contains() is extremely slow.
LINQ Any() looks a little bit faster, but still too slow.
Are there any alternatives to perform the search faster on a generic list? Or maybe I should use another storage?
I would use a Dictionary<string, HashSet<string>> mapping one key to all its values.
Here is a full solution. First, write a couple of extension methods to add a (key,value) pair to your Dictionary and another one to get all (key,value) pairs. Note that I use arbitrary types for keys and values, you can substitute this with string without problem.
You can even write these methods somewhere else instead of as extensions, or not use methods at all and just use this code somewhere in your program.
public static class Program
{
public static void Add<TKey, TValue>(
this Dictionary<TKey, HashSet<TValue>> data, TKey key, TValue value)
{
HashSet<TValue> values = null;
if (!data.TryGetValue(key, out values)) {
// first time using this key? create a new HashSet
values = new HashSet<TValue>();
data.Add(key, values);
}
values.Add(value);
}
public static IEnumerable<KeyValuePair<TKey, TValue>> KeyValuePairs<TKey, TValue>(
this Dictionary<TKey, HashSet<TValue>> data)
{
return data.SelectMany(k => k.Value,
(k, v) => new KeyValuePair<TKey, TValue>(k.Key, v));
}
}
Now you can use it as follows:
public static void Main(string[] args)
{
Dictionary<string, HashSet<string>> data = new Dictionary<string, HashSet<string>>();
data.Add("k1", "v1.1");
data.Add("k1", "v1.2");
data.Add("k1", "v1.1"); // already in, so nothing happens here
data.Add("k2", "v2.1");
foreach (var kv in data.KeyValuePairs())
Console.WriteLine(kv.Key + " : " + kv.Value);
}
Which will print this:
k1 : v1.1
k1 : v1.2
k2 : v2.1
If your key mapped to a List<string> then you would need to take care of duplicates yourself. HashSet<string> does that for you already.
I guess that Dictionary<string, List<string>> will do the trick.
I would consider using some in-proc NoSQL database like RavenDB (RavenDB Embedded in this case) as they state on their website:
RavenDB can be used for application that needs to store millions of records and has fast query times.
Using it is requires no big boilerplate (example from RavenDB website):
var myCompany = new Company
{
Name = "Hibernating Rhinos",
Employees = {
new Employee
{
Name = "Ayende Rahien"
}
},
Country = "Israel"
};
// Store the company in our RavenDB server
using (var session = documentStore.OpenSession())
{
session.Store(myCompany);
session.SaveChanges();
}
// Create a new session, retrieve an entity, and change it a bit
using (var session = documentStore.OpenSession())
{
Company entity = session.Query<Company>()
.Where(x => x.Country == "Israel")
.FirstOrDefault();
// We can also load by ID: session.Load<Company>(companyId);
entity.Name = "Another Company";
session.SaveChanges(); // will send the change to the database
}
To make a unique list you want to use .Distinct() to generate it, not .Contains(). However whatever class holds your strings must implement .GetHashCode() and .Equals() correctly to get good performance or you must pass in a custom comparer.
Here is how you could do it with a custom comparer
private static void Main(string[] args)
{
List<KeyValuePair<string, string>> giantList = Populate();
var uniqueItems = giantList.Distinct(new MyStringEquater()).ToList();
}
class MyStringEquater : IEqualityComparer<KeyValuePair<string, string>>
{
//Choose which comparer you want based on if you want your comparisions to be case sensitive or not
private static StringComparer comparer = StringComparer.OrdinalIgnoreCase;
public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y)
{
return comparer.Equals(x.Key, y.Key) && comparer.Equals(x.Value, y.Value);
}
public int GetHashCode(KeyValuePair<string, string> obj)
{
unchecked
{
int x = 27;
x = x*11 + comparer.GetHashCode(obj.Key);
x = x*11 + comparer.GetHashCode(obj.Value);
return x;
}
}
}
Also per your comment in the other answer you could also use the above comparer in a HashSet and have it store your unique items that way. You just need to pass in the comparer in to the constructor.
var hashSetWithComparer = new HashSet<KeyValuePair<string,string>(new MyStringEquater());
You will most likely see an improvement if you use a HashSet<KeyValuePair<string, string>>.
The test below finishes on my machine in about 10 seconds. If I change...
var collection = new HashSet<KeyValuePair<string, string>>();
...to...
var collection = new List<KeyValuePair<string, string>>();
...I get tired of waiting for it to complete (more than a few minutes).
Using a KeyValuePair<string, string> has the advantage that equality is determined by the values of Key and Value. Since strings are interned, and KeyValuePair<TKey, TValue> is a struct, pairs with the same Key and Value will be considered equal by the runtime.
You can see that equality with this test:
var hs = new HashSet<KeyValuePair<string, string>>();
hs.Add(new KeyValuePair<string, string>("key", "value"));
var b = hs.Contains(new KeyValuePair<string, string>("key", "value"));
Console.WriteLine(b);
One thing that's important to remember, though, is that the equality of pairs depends on the internment of strings. If, for some reason, your strings aren't interned (because they come from a file or something), the equality probably won't work.
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace ConsoleApplication1 {
internal class Program {
static void Main(string[] args) {
var key = default(string);
var value = default(string);
var collection = new HashSet<KeyValuePair<string, string>>();
for (var i = 0; i < 5000000; i++) {
if (key == null || i % 2 == 0) {
key = "k" + i;
}
value = "v" + i;
collection.Add(new KeyValuePair<string, string>(key, value));
}
var found = 0;
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < 5000000; i++) {
if (collection.Contains(new KeyValuePair<string, string>("k" + i, "v" + i))) {
found++;
}
}
sw.Stop();
Console.WriteLine("Found " + found);
Console.WriteLine(sw.Elapsed);
Console.ReadLine();
}
}
}
Have you tried using a Hashset? Much quicker than lists when large numbers are involved although I don't know if it'd still be too slow.
This answer has a lot of information: HashSet vs. List performance

Get Dictionary key by using the dictionary value

How to get the dictionary key by using the dictionary value?
when getting the value using the key its like this:
Dictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(1, "a");
Console.WriteLine(dic[1]);
Console.ReadLine();
How to do the opposite?
A dictionary is really intended for one way lookup from Key->Value.
You can do the opposite use LINQ:
var keysWithMatchingValues = dic.Where(p => p.Value == "a").Select(p => p.Key);
foreach(var key in keysWithMatchingValues)
Console.WriteLine(key);
Realize that there may be multiple keys with the same value, so any proper search will return a collection of keys (which is why the foreach exists above).
Brute force.
int key = dic.Where(kvp => kvp.Value == "a").Select(kvp => kvp.Key).FirstOrDefault();
You can also use the following extension method to get key from dictionary by value
public static class Extensions
{
public static bool TryGetKey<K, V>(this IDictionary<K, V> instance, V value, out K key)
{
foreach (var entry in instance)
{
if (!entry.Value.Equals(value))
{
continue;
}
key = entry.Key;
return true;
}
key = default(K);
return false;
}
}
the usage is also so simple
int key = 0;
if (myDictionary.TryGetKey("twitter", out key))
{
// successfully got the key :)
}
easy way for get one key:
public static TKey GetKey<TKey,TValue>(Dictionary<TKey, TValue> dictionary, TValue Value)
{
List<TKey> KeyList = new List<TKey>(dictionary.Keys);
foreach (TKey key in KeyList)
if (dictionary[key].Equals(Value))
return key;
throw new KeyNotFoundException();
}
and for multiples keys:
public static TKey[] GetKeys<TKey, TValue>(Dictionary<TKey, TValue> dictionary, TValue Value)
{
List<TKey> KeyList = new List<TKey>(dictionary.Keys);
List<TKey> FoundKeys = new List<TKey>();
foreach (TKey key in KeyList)
if (dictionary[key].Equals(Value))
FoundKeys.Add(key);
if (FoundKeys.Count > 0)
return FoundKeys.ToArray();
throw new KeyNotFoundException();
}
I realize this is an old question but wanted to add something I thought of.
If you know there will be only one key to one value and you'll have to look up via value as well as key; you can create two separate dictionaries. One with the original key as the key and value as the value and the second with the key as the value and value as the key.
Now a side note about this; it does use up more machine resources but I'm guessing it's faster then brute forcing through LINQ and foreach.

Dictionary enumeration in C#

How do I enumerate a dictionary?
Suppose I use foreach() for dictionay enumeration. I can't update a key/value pair inside foreach(). So I want some other method.
To enumerate a dictionary you either enumerate the values within it:
Dictionary<int, string> dic;
foreach(string s in dic.Values)
{
Console.WriteLine(s);
}
or the KeyValuePairs
foreach(KeyValuePair<int, string> kvp in dic)
{
Console.WriteLine("Key : " + kvp.Key.ToString() + ", Value : " + kvp.Value);
}
or the keys
foreach(int key in dic.Keys)
{
Console.WriteLine(key.ToString());
}
If you wish to update the items within the dictionary you need to do so slightly differently, because you can't update the instance while enumerating. What you'll need to do is enumerate a different collection that isn't being updated, like so:
Dictionary<int, string> newValues = new Dictionary<int, string>() { 1, "Test" };
foreach(KeyValuePair<int, string> kvp in newValues)
{
dic[kvp.Key] = kvp.Value; // will automatically add the item if it's not there
}
To remove items, do so in a similar way, enumerating the collection of items we want to remove rather than the dictionary itself.
List<int> keys = new List<int>() { 1, 3 };
foreach(int key in keys)
{
dic.Remove(key);
}
In answer to the problem "I can't update value/key inside foreach()", you cannot modify a collection while enumerating it. I would approach this by making a copy of the Keys collection:
Dictionary<int,int> dic=new Dictionary<int, int>();
//...fill the dictionary
int[] keys = dic.Keys.ToArray();
foreach (int i in keys)
{
dic.Remove(i);
}
Foreach. There are three ways: You can enumerate over the Keys property, over the Values property or over the dictionary itself which is an enumerator of KeyValuePair<TKey, TValue>.
I just answered the same (updated) question for lists, so here's the same thing for dictionaries.
public static void MutateEach(this IDictionary<TKey, TValue> dict, Func<TKey, TValue, KeyValuePair<TKey, TValue>> mutator)
{
var removals = new List<TKey>();
var additions = new List<KeyValuePair<TKey, TValue>>();
foreach (var pair in dict)
{
var newPair = mutator(pair.Key, pair.Value);
if ((newPair.Key != pair.Key) || (newPair.Value != pair.Value))
{
removals.Add(pair.Key);
additions.Add(newPair);
}
}
foreach (var removal in removals)
dict.Remove(removal);
foreach (var addition in additions)
dict.Add(addition.Key, addition.Value);
}
Note that we have to do the updates outside the loop, so we aren't modifying the dictionary as we enumerate it. Also this detects clashes caused by making two keys the same - it will throw (due to the use of Add).
Example - make all keys lowercase and trim all values, with a Dictionary<string, string>:
myDict.MutateEach(key => key.ToLower(), value => value.Trim());
If the keys are not unique when made lowercase, this will throw.

Categories

Resources