Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Indexed collections (Indexed dictionary)

5.00/5 (4 votes)
1 May 2016CPOL4 min read 16.4K   387  
Dictionary with keys and indexes

Introduction

Indexed dictionary is the first collection object in the indexed collections family. The ordinary dictionary or hashtable usually satisfy software developer needs, but sometimes there is a need to find stored item not only by keys, but by some additional property as well. It is just like in database where we have a key by row and we index certain fields. For this purpose I propose to use the following in the dictionary .

Background

Imagine you have a dictionary of persons, where the key is person ID. Assume an object has first name and last name. There is no difficulties to fetch person by ID, but what if we want to search person by last name as well. We have only two possibilities. The first one is: each time we need to find a person by last name just run over the dictionary and look for specific last name. The second one is to maintain an additional dictionary where we store some index the for original dictionary last name.

The Indexed Dictionary allows you to use as regular dictionary on the one hand, and define index properties on the other.

IMPORTANT - This Alpha version and it is NOT thread safety. I am planning to add and thread safety indexed dictionary to IndexedCollections name space as well as develop a Java version of it.

Using the code

You can add reference to the Indexed dictionary either downloading and compiling the solution or from NuGet, using NuGet  package manager console using the following command:

Install-Package IndexedCollections

Let’s go over the example with person from above and will solve using Indexed Dictionary. Assume, we have a person object, which looks like:

C#
class Person
{
   [Key]
   public int Id { get; set; }

    [Index]
    public string LastName { get; set; }

    [Index]
    public string FirstName { get; set; }

    public override string ToString()
    {
        return string.Format("{0} - {1},{2}", Id, LastName, FirstName);
    }
 }

Key - attribute defines a key property in the class. Indexed Dictionary will look for this attribute. In case it will not find it will raise an exception of NoKeyPropertyException.

Index - attribute defines a property which will used as index. It means, that the the is marked as a field, that the dictionary can queried by. There two types of indexes: Unique and not Unique. The only difference between them is, that ,surprisingly, the values of unique property should be unique in the dictionary.

IMPORTANT All the properties, which are marked either as Key or as Index must implement GetHashCode method, and it must return different hash codes for different values and identical hash codes for identical values.

Now, let’s define the dictionary:

C#
IndexedDictionary<int,Person> people = new IndexedDictionary<int, Person>();

It pretty reminds the declaration of regular dictionary :
int - type of key 
Person - type of value

Add item

Now let’s add an item 
Step one: create a Person instance:

C#
Person p1 = new Person(){Id = 1,First = " John", LastName = "Johnson"}

Step two: add the instance to dictionary:

C#
people.Add(p1);

We do not pass the key value explicitly, since the property Id of Person class had been marked as Key already.
Another way to add item to the dictionary is to use the indexer ([]).

C#
people[p1.Id]  = p1

Fetching data

There are two different ways to fetch item from indexed dictionary.

1 - using indexer

C#
Person p = people[1];

2 - using the GetByTemplate method

C#
Person t = new Person(){Id = 1,FirstName = "John"};
Person [] p  = people.GetByTemplate(t,LogicOperator.OR,true);

Let’s go over the parameters of the method. The very first parameter is template according which we are going to select the items. Indexed dictionary takes into account properties which are marked either as Key or as Index. If I wanted to match items by indexed properties only, ignoring the key, I must provide the very last parameter as false, otherwise it should be true. It is a default parameter and its default value is true.

The second parameter tells the dictionary how to perform matching of the items. OR - tells, that match of any of marked property of provided template will add item to result set AND - tells, that only match of all marked properties of provided template will add item to result set
AND_IGNORE_NULLS - just like and, but the template marked properties, which have nulls as values will be ignored during the matching process.
NOT - Items, which have at least one not identical marked property value will be added to the result set.

The third parameter tells dictionary either encounter key property in matching process or not. If value of this parameter is false, the key property will be ignored in the matching process. This default parameter and its default value is true.

ForEach

The Indexed dictionary implements both IEnumerable and IEnumerator interfaces, so you definitely can perform iteration using foreach statement.

Demo

The solution includes Demo project. You are welcome to run and take a look on the code, which uses the IndexedDictionary. The demo program stores in indexed dictionary people. It stores theirs ID, which is dictionary key, first name and last name, which are indexes.

In the top frame you can add person, while in the bottom frame yu can find and delete data of the people. You are welcome to look at the code to undestand the basic usage of the IndexedDictionary.

Image 1

License

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