ListDictionary: An Improved OrderedDictionary





5.00/5 (8 votes)
ListDictionary provided Dictionary-like functionality with ordered enumeration
Introduction
I've been on a CSV kick, slinging List<string>
s of column names and Dictionary<string, object>
s of column data. I realized that some of my column data was out of column name order. Turns out that enumerating the data Dictionary
as KeyValuePair
does not return data in any particular order. So I needed an orderly dictionary.
Online articles said use System.Collection.Specialized
's OrderedDictionary
. Great, it's ordered! But it's not "generic", it's object-to-object, needing casting all over the place for even light duty. Yuck!
So I said, "Screw it!" and decided to write something to do the job. It would have a Dictionary
inside for quick lookups, and a List
inside to keep things in order. I call it ListDictionary
. Not designed for large amounts of data, focused on orderly behavior, I hope it serves you well.
using System;
using System.Collections.Generic;
using System.Linq;
namespace metastrings
{
public class ListDictionary<K, V> where K : IComparable<K>
{
public List<KeyValuePair<K, V>> Entries => m_list;
public IEnumerable<K> Keys => m_list.Select(kvp => kvp.Key);
public IEnumerable<V> Values => m_list.Select(kvp => kvp.Value);
public V this[K key]
{
get { return m_dict[key]; }
set { Set(key, value); }
}
public int Count => m_list.Count;
public bool ContainsKey(K key) => m_dict.ContainsKey(key);
public K FirstKey => m_list[0].Key;
public void Set(K key, V val)
{
bool added = false;
if (m_dict.ContainsKey(key))
{
for (int i = 0; i < m_list.Count; ++i)
{
K curKey = m_list[i].Key;
if (curKey.CompareTo(key) == 0)
{
m_list[i] = new KeyValuePair<K, V>(key, val);
added = true;
break;
}
}
}
if (!added)
m_list.Add(new KeyValuePair<K, V>(key, val));
m_dict[key] = val;
}
private List<KeyValuePair<K, V>> m_list = new List<KeyValuePair<K, V>>();
private Dictionary<K, V> m_dict = new Dictionary<K, V>();
}
}
Not a lot to it. Not fully fleshed out, I just added the stuff I needed, and some unit tests:
ListDictionary<string, int> dict = new ListDictionary<string, int>();
dict["foo"] = 1;
dict["bar"] = 2;
Assert.AreEqual(1, dict["foo"]);
Assert.AreEqual(2, dict["bar"]);
Assert.AreEqual(2, dict.Count);
Assert.AreEqual("foo", dict.FirstKey);
Assert.AreEqual("foo", dict.Entries.First().Key);
Assert.AreEqual(1, dict.Entries.First().Value);
Assert.AreEqual("bar", dict.Entries.Last().Key);
Assert.AreEqual(2, dict.Entries.Last().Value);
Assert.IsTrue(dict.Keys.Contains("foo"));
Assert.IsTrue(dict.Values.Contains(1));
Assert.IsTrue(dict.Keys.Contains("bar"));
Assert.IsTrue(dict.Values.Contains(2));
Assert.IsTrue(dict.ContainsKey("foo"));
Assert.IsTrue(dict.ContainsKey("bar"));
Assert.IsTrue(!dict.ContainsKey("blet"));
dict["foo"] = 42;
Assert.AreEqual(42, dict["foo"]);
Points of Interest
Got to use indexers with get
and set
. Got to use IComparable
. Used OrderedDictionary
enough to hate it. What did people do before .NET 2.0?
Attached is the ListDictionary
class, and a few other juicy morsels. Enjoy!
History
- 20th May, 2020: Initial version