vizcayno
vizcayno

Reputation: 1233

How to get the relative position of a Dictionary element?

I have the next C# code:

    Dictionary<string, int> d = new Dictionary<string, int>();
    d.Add("a", 3);
    d.Add("b", 1);
    d.Add("c", 0);
    d.Add("d", -1);
    d.Add("e", -9);

When searching the key "c" I want to get the position of this key, i.e. 2. If I look for the key "e", I want to get 4. If the element is not found the relative position could be -1.

Added: Unless you have a better idea, I want to populate a matrix with certain values in a row number indicated by the relative position of a dictionary element found. The same applies for the column but using a different dictionary. An example:

     n4   n2   n1   n3  n9  . . . 
a   4/4
b              2         8
c
d                  8/2
e         4/3
.
.
.

Where a,b,c,d,e,... are the keys of dictionay "d" and n4,n2,n3,n9 are the keys of a second dictionary.

How can I get this?

Upvotes: 3

Views: 15494

Answers (5)

TTT
TTT

Reputation: 29084

This should do the trick:

d.Keys.ToList().IndexOf("c");

Please Note that the O(1) time lookup offered by the Dictionary is lost when converting to the List, because Lists are inherently O(n). So if your Dictionary has a large number of elements, you're probably better off using another Dictionary or Matrix dimension to store the positions, since retrieving them in this manner will likely be slower. In fact, you should probably assume that the one-liner above is similar to:

GetDictKeyPos(d, "c");

public int GetDictKeyPos(Dictionary<string, int> d, string key)
{
    for (int i = 0; i < d.Count; ++i)
    {
        if (d.ElementAt(i).Key == key)
            return i;
    }
    return -1;
}

As a side note, if you are trying to get the position, you're probably making the assumption that the position is preserved. Microsoft says don't count on it, but in practice you'll discover that you probably can count on it. (I've never seen position not be preserved.) That being said, until Microsoft admits that, "Yeah, yeah, we've been holding out on you: position actually is preserved in a Dictionary. We just didn't want to admit it because we wanted to be able to change it if we found a better implementation, but now we know we're going to leave it, so here ya go...", you probably shouldn't assume that position is preserved.

Lastly, if you are planning to take your chances and assume it's preserved, and you also plan to use the above method to get the position, then consider storing the keys in a List instead, since the lookup time will be the same, and List order is guaranteed to be preserved.

Upvotes: 3

Brian Gideon
Brian Gideon

Reputation: 48959

You will not be able to use any of the builtin collection data structures including KeyedCollection. However, you can easily make your own collection class by deriving from Collection and which contains a Dictionary internally for quick lookups on the key. The Collection class itself provides the ability for indexed retrieval.

public class KeyValueCollection<TKey, TValue> : Collection<KeyValuePair<TKey, TValue>>
{
    private Dictionary<TKey, TValue> m_Dictionary = new Dictionary<TKey, TValue>();

    public TValue GetValue(TKey key)
    {
        return m_Dictionary[key];
    }

    public void Add(TKey key, TValue value)
    {
        m_Dictionary.Add(key, value);
        base.Add(new KeyValuePair<TKey, TValue>(key, value));
    }

    protected override void ClearItems()
    {
        m_Dictionary.Clear();
        base.ClearItems();
    }

    protected override void InsertItem(int index, KeyValuePair<TKey, TValue> item)
    {
        m_Dictionary.Add(item.Key, item.Value);
        base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {

        m_Dictionary.Remove(this[index].Key);
        base.RemoveItem(index);
    }

    protected override void SetItem(int index, KeyValuePair<TKey, TValue> item)
    {
        m_Dictionary[this[index].Key] = item.Value;
        base.SetItem(index, item);
    }
}

Upvotes: 0

NullUserException
NullUserException

Reputation: 85478

Dictionaries have no implied order of key-value pairs. If you need the "position," you are using them the wrong way.

On your edit: If you are implementing a matrix, your best bet would be to use a multidimensional array. Eg:

int[,] matrix = new int[3, 2] { {1, 2}, {3, 4}, {5, 6} };

Is equivalent to a matrix like:

1 2
3 4
5 6

You can access its elements using matrix[i][j]; eg matrix[0][0] is 1, matrix[0][1] is 2, etc.

Upvotes: 1

rkg
rkg

Reputation: 5719

If you are really looking for that functionality, why don't you maintain an auxilary data structure which maintains the order in which you added the elements

(OR)

Probably you want to just maintain a List of Structures which store

   [{"a",-1},{"b",1},{"c",0},{"d",-1},{"e",-9}]

Upvotes: -1

Jon Skeet
Jon Skeet

Reputation: 1503090

There's no such thing as a "position" within a Dictionary<,> - it's an unordered collection.

There are similar collections sorted by key - SortedList<,> and SortedDictionary<,>. Note that those are ordered by key rather than insertion time though. It's not clear which you want.

Upvotes: 10

Related Questions