Click here to Skip to main content
14,932,691 members
Articles / Programming Languages / C#
Tip/Trick
Posted 19 May 2020

Tagged as

Stats

5.2K views
82 downloads
8 bookmarked

ListDictionary: An Improved OrderedDictionary

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
19 May 2020CPOL1 min read
ListDictionary provided Dictionary-like functionality with ordered enumeration
Some of my column data in CSV was out of column name order. Enumerating the data Dictionary as KeyValuePair did not return data in any particular order, and using System.Collection.Specialized's OrderedDictionary was cumbersome. So, I created my own orderly dictionary called ListDictionary which is discussed in this tip.

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.

C#
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:

C#
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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Michael Sydney Balloni
Software Developer
United States United States
Michael Balloni is a manager of software development at a cybersecurity software and services provider.

Check out https://www.michaelballoni.com for all the programming fun he's done over the years.

He has been developing software since 1994, back when Mosaic was the web browser of choice. IE 4.0 changed the world, and Michael rode that wave for five years at a .com that was a cloud storage system before the term "cloud" meant anything. He moved on to a medical imaging gig for seven years, working up and down the architecture of a million-lines-code C++ system.

Michael has been at his current cybersecurity gig for six years, making his way into management. He still loves to code, so he sneaks in as much as he can at work and at home.

Comments and Discussions

 
QuestionListDictionary: An Improved OrderedDictionary Pin
Ron Murphy21-May-20 9:36
MemberRon Murphy21-May-20 9:36 
QuestionSortedDictionary Pin
George Swan19-May-20 21:03
MemberGeorge Swan19-May-20 21:03 
AnswerRe: SortedDictionary Pin
honey the codewitch19-May-20 21:12
mvahoney the codewitch19-May-20 21:12 
GeneralRe: SortedDictionary Pin
George Swan19-May-20 21:53
MemberGeorge Swan19-May-20 21:53 
GeneralRe: SortedDictionary Pin
honey the codewitch20-May-20 5:25
mvahoney the codewitch20-May-20 5:25 
GeneralRe: SortedDictionary Pin
George Swan20-May-20 6:58
MemberGeorge Swan20-May-20 6:58 
QuestionThere are some significant differences between your dictionary and a standard generic dictionary interface Pin
honey the codewitch19-May-20 20:58
mvahoney the codewitch19-May-20 20:58 
AnswerRe: There are some significant differences between your dictionary and a standard generic dictionary interface Pin
Michael Sydney Balloni20-May-20 7:20
professionalMichael Sydney Balloni20-May-20 7:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.