Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unique key-value-pair collection

Is there any structure that allows BOTH of these operations:

  • collection.TryGetValue(TKey, out TValue)
  • collection.TryGetKey(TValue, out TKey)

In a better time than O(n)?

My problem:

I basically need to be able to retrieve key's value or value's key really fast, without duplicating the memory (so two dictionaries are out of question).

Very important note: all the keys are unique and all the values are unique. Having this information I feel it should be possible to accomplish this task in a better time than just O(1) for .TryGetValue and O(n) for .TryGetKey.

EDIT:

In my case, I have a mapping between strings and ints. There are ~650,000 key-value pairs of texts and their IDs. So I basically want to get the string with a specific ID but also the ID of a certain string.

like image 471
Patryk Golebiowski Avatar asked Dec 11 '15 15:12

Patryk Golebiowski


People also ask

What is a collection of key-value pairs?

A key-value database is a type of nonrelational database that uses a simple key-value method to store data. A key-value database stores data as a collection of key-value pairs in which a key serves as a unique identifier. Both keys and values can be anything, ranging from simple objects to complex compound objects.

How do you generate key-value pairs?

If we suppose that your keyvaluepair has as a key a string and as a value an int, then you could try this one: clsName. PropertyName = new KeyValuePair<string, int>("keyName", 2); You don't need to use the any Add method.

What does key-value pair mean?

A key-value pair (KVP) is a set of two linked data items: a key, which is a unique identifier for some item of data, and the value, which is either the data that is identified or a pointer to the location of that data. Key-value pairs are frequently used in lookup tables, hash tables and configuration files.

Is dictionary unique c#?

A dictionary, also called an associative array, is a collection of unique keys and a collection of values, where each key is associated with one value. Retrieving and adding values is very fast. Dictionaries take more memory because for each value there is also a key.


1 Answers

To get better than O(n) you will need to use a 2nd dictionary. However as you mentioned you are using structs and are concerned about memory usage with a 2nd dictionary having a duplicate copy of the struct.

One way around this is box the struct value inside a object then share the boxed object in the two dictionaries. If you use inherit from DictionaryBase this is actually quite easy to implement.

public sealed class TwoWayDictionary<TKey, TValue> : DictionaryBase
{
    Hashtable reverseLookup = new Hashtable();

    public void Add(TKey key, TValue value)
    {
        this.Dictionary.Add(key, value);
    }

    public void Remove(TKey key)
    {
        this.Dictionary.Remove(key);
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        object lookup = Dictionary[key];
        if (lookup == null)
        {
            value = default(TValue);
            return false;
        }
        else
        {
            value = (TValue)lookup;
            return true;
        }
    }

    public bool TryGetKey(TValue value, out TKey key)
    {
        object lookup = reverseLookup[value];
        if (lookup == null)
        {
            key = default(TKey);
            return false;
        }
        else
        {
            key = (TKey)lookup;
            return true;
        }
    }

    //If OnInsertComplete or OnSetComplete raises a exception DictionaryBase will 
    // roll back the operation it completed.
    protected override void OnInsertComplete(object key, object value)
    {
        reverseLookup.Add(value, key);
    }

    protected override void OnSetComplete(object key, object oldValue, object newValue)
    {
        if(reverseLookup.Contains(newValue))
            throw new InvalidOperationException("Duplicate value");
        if(oldValue != null)
            reverseLookup.Remove(oldValue);
        reverseLookup[newValue] = key;
    }

    protected override void OnRemoveComplete(object key, object value)
    {
        reverseLookup.Remove(value);
    }
}

The Dictionary and reverseLookup dictionaries will share the same references so it will have a smaller memory footprint than using two strongly typed dictionaries with large structs.

Without writing a full Dictionary<TKey, TValue> implementation that usees two internal bucket collections for keys and values and two linked lists for the chains off of the buckets I don't think you can get much better results.

like image 91
Scott Chamberlain Avatar answered Sep 23 '22 02:09

Scott Chamberlain