?
Solved

Key/pair and keep order

Posted on 2012-09-10
11
Medium Priority
?
722 Views
Last Modified: 2012-09-11
Hi
I have list of Key/Pair values
I want to maintain order or them (they are not necessarily alphabetical order), but also able to search by key). I need to be able to add, delete, update list.
Key is a string,
Value is a custom object


I've tried a few different types such as Hashtable, Dictionary but cannot find correct one to do this
(I find ordering is random for example)

Probably this is an easy one.

Thanks
0
Comment
Question by:rwallacej
  • 5
  • 4
  • 2
11 Comments
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 38383514
Have you tried SortedDictionary? You can create a custom Comparer to enforce a particular ordering.
0
 

Author Comment

by:rwallacej
ID: 38383540
I tried sorted dictionary but found it ordered by the string key, I don't know how it would work sorting by order which items added to list
0
 
LVL 86

Assisted Solution

by:Mike Tomlinson
Mike Tomlinson earned 500 total points
ID: 38383679
How many items are we talking here?

If a relatively small number then just use a List(Of KeyValuePair(Of KeyType, ValueType)).  To get an item "by key" then you'd just iterate over the list until you find the matching key.  The values will be ordered based on entry order and you can access/add/remove them by index.

For larger set you can sacrifice memory and keep two internal lists so you have access by key and index.

...but basically there are no built-in collections that give you access by key and maintain the order of entry of the values.
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 38383902
...but basically there are no built-in collections that give you access by key and maintain the order of entry of the values.
Quite to the contrary, my good sir. There is the OrderedDictionary. With this class, you can do just that. However, the downside of this class is that it stores its keys and values as type object, so you would need to be careful with your inserts, and you would need to cast any retrievals from the collection.

So I think we can ammend Idle_Mind's comment to, "...but basically there are no built-in generic collections that give you access by key and maintain the order of entry of the values." That, I believe, holds true.
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 38384011
Here's the beginnings of a custom class that would give you the desired functionality. It uses the aforementioned OrderedDictionary under the hood. I did this because since it is an implementation detail, and because I created the class as generic, you can enforce that no foreign types are inserted into the data store, thus avoiding the need for run-time type checking. You would incur a slight performance degradation (probably not noticeable to you) whenever you used value types for either TKey or TValue due to boxing conversions. However, I think it would suit your needs.

public class IndexedDictionary<TKey, TValue> : System.Collections.Generic.IDictionary<TKey, TValue>, System.Collections.Generic.IList<TValue>
{
    private System.Collections.Specialized.OrderedDictionary _dataStore;

    public IndexedDictionary()
    {
        this._dataStore = new System.Collections.Specialized.OrderedDictionary();
    }

    public int IndexOf(TValue item)
    {
        for (int i = 0; i < this._dataStore.Count; i++)
        {
            if (this._dataStore[i].Equals(item))
            {
                return i;
            }
        }

        return -1;
    }

    public void Insert(int index, TValue item)
    {

    }

    public void RemoveAt(int index)
    {
        this._dataStore.RemoveAt(index);
    }

    public TValue this[int index]
    {
        get
        {
            return (TValue)this._dataStore[index];
        }
        set
        {
            this._dataStore[index] = value;
        }
    }

    public void Add(TValue item)
    {

    }

    public void Clear()
    {
        this._dataStore.Clear();
    }

    public bool Contains(TValue item)
    {
        return (this.IndexOf(item) > -1);
    }

    public void CopyTo(TValue[] array, int arrayIndex)
    {

    }

    public int Count
    {
        get { throw new NotImplementedException(); }
    }

    public bool IsReadOnly
    {
        get { throw new NotImplementedException(); }
    }

    public bool Remove(TValue item)
    {
        throw new NotImplementedException();
    }

    public IEnumerator<TValue> GetEnumerator()
    {
        throw new NotImplementedException();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    public void Add(TKey key, TValue value)
    {
        throw new NotImplementedException();
    }

    public bool ContainsKey(TKey key)
    {
        throw new NotImplementedException();
    }

    public ICollection<TKey> Keys
    {
        get { throw new NotImplementedException(); }
    }

    public bool Remove(TKey key)
    {
        throw new NotImplementedException();
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        throw new NotImplementedException();
    }

    public ICollection<TValue> Values
    {
        get { throw new NotImplementedException(); }
    }

    public TValue this[TKey key]
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public void Add(KeyValuePair<TKey, TValue> item)
    {
        throw new NotImplementedException();
    }

    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        throw new NotImplementedException();
    }

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        throw new NotImplementedException();
    }

    public bool Remove(KeyValuePair<TKey, TValue> item)
    {
        throw new NotImplementedException();
    }

    IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

Open in new window


Usage would be along the lines of:


static void Main(string[] args)
{
    IndexedDictionary<int, string> myDictionary = new IndexedDictionary<int, string>();

    myDictionary.Add(1, "one");
}

Open in new window

0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 38384068
Thanks for the correction kaufmed!  =)

I'd forgotten about OrderedDictionary(), probably exactly because it doesn't have a generic implementation.

I
0
 

Author Comment

by:rwallacej
ID: 38384348
Thanks guys.  It's VB.net I'm using and the above code didn't convert right.  
However, I should probably take a "step back" per Idle_Mind comment. There are not a lot of items, say 25 max, so use iteration.
That said, I'd be interested to see the code in VB if its not too much trouble to convert it?
0
 
LVL 75

Accepted Solution

by:
käµfm³d   👽 earned 1500 total points
ID: 38384403
Ah, I see the issue. It's mainly because I attempted to implement both the IDictionary and IList interfaces on that class. In hindsight, it would probably be a might easier to just avoid the interfaces unless you absolutely needed them (for OOP goodness). Removing one or the other should make compilation a tad simpler.

Here I've removed the IList interface and added an overload for the default Item property to allow for access by index. Please note:  I haven't tested it since I am currently at work. I can refine it later this evening, but I believe it should be functional in its current state.

Public Class IndexedDictionary(Of TKey, TValue)
    Implements System.Collections.Generic.IDictionary(Of TKey, TValue)

    Private _dataStore As System.Collections.Specialized.OrderedDictionary

    Public Sub New()
        Me._dataStore = New System.Collections.Specialized.OrderedDictionary()
    End Sub

    Public Sub Add(item As System.Collections.Generic.KeyValuePair(Of TKey, TValue)) Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of TKey, TValue)).Add
        Me._dataStore.Add(item.Key, item.Value)
    End Sub

    Public Sub Clear() Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of TKey, TValue)).Clear
        Me._dataStore.Clear()
    End Sub

    Public Function Contains(item As System.Collections.Generic.KeyValuePair(Of TKey, TValue)) As Boolean Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of TKey, TValue)).Contains
        Return Me._dataStore.Contains(item.Key)
    End Function

    Public Sub CopyTo(array() As System.Collections.Generic.KeyValuePair(Of TKey, TValue), arrayIndex As Integer) Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of TKey, TValue)).CopyTo

    End Sub

    Public ReadOnly Property Count As Integer Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of TKey, TValue)).Count
        Get
            Return Me._dataStore.Count
        End Get
    End Property

    Public ReadOnly Property IsReadOnly As Boolean Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of TKey, TValue)).IsReadOnly
        Get
            returm(Me._dataStore.IsReadOnly)
        End Get
    End Property

    Public Function Remove(item As System.Collections.Generic.KeyValuePair(Of TKey, TValue)) As Boolean Implements System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of TKey, TValue)).Remove
        Me._dataStore.Remove(item.Key)
    End Function

    Public Sub Add1(key As TKey, value As TValue) Implements System.Collections.Generic.IDictionary(Of TKey, TValue).Add
        Me._dataStore.Add(key, value)
    End Sub

    Public Function ContainsKey(key As TKey) As Boolean Implements System.Collections.Generic.IDictionary(Of TKey, TValue).ContainsKey
        Return Me._dataStore.Contains(key)
    End Function

    Default Public Overloads Property Item(ByVal index As Integer) As TValue
        Get
            Return DirectCast(Me._dataStore(index), TValue)
        End Get
        Set(value As TValue)
            Me._dataStore(index) = value
        End Set
    End Property

    Default Public Overloads Property Item(key As TKey) As TValue Implements System.Collections.Generic.IDictionary(Of TKey, TValue).Item
        Get
            Return DirectCast(Me._dataStore(key), TValue)
        End Get
        Set(value As TValue)
            Me._dataStore(key) = value
        End Set
    End Property

    Public ReadOnly Property Keys As System.Collections.Generic.ICollection(Of TKey) Implements System.Collections.Generic.IDictionary(Of TKey, TValue).Keys
        Get
            Return Me._dataStore.Keys
        End Get
    End Property

    Public Function Remove1(key As TKey) As Boolean Implements System.Collections.Generic.IDictionary(Of TKey, TValue).Remove
        Me._dataStore.Remove(key)
    End Function

    Public Function TryGetValue(key As TKey, ByRef value As TValue) As Boolean Implements System.Collections.Generic.IDictionary(Of TKey, TValue).TryGetValue

    End Function

    Public ReadOnly Property Values As System.Collections.Generic.ICollection(Of TValue) Implements System.Collections.Generic.IDictionary(Of TKey, TValue).Values
        Get

        End Get
    End Property

    Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of System.Collections.Generic.KeyValuePair(Of TKey, TValue)) Implements System.Collections.Generic.IEnumerable(Of System.Collections.Generic.KeyValuePair(Of TKey, TValue)).GetEnumerator
        Return Me._dataStore.GetEnumerator()
    End Function

    Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Return GetEnumerator()
    End Function
End Class

Open in new window

0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 38384414
P.S.

There might be an issue when using keys of type Integer. I am not certain which version of the Item property would be called (though I suspect it would be the one with the explicit Integer type). That bit of code may need to be reworked.
0
 

Author Comment

by:rwallacej
ID: 38384426
thanks, I'll try tomorrow,
0
 

Author Closing Comment

by:rwallacej
ID: 38386541
works a treat, thank-you
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In real business world data are crucial and sometimes data are shared among different information systems. Hence, an agreeable file transfer protocol need to be established.
High user turnover can cause old/redundant user data to consume valuable space. UserResourceCleanup was developed to address this by automatically deleting user folders when the user account is deleted.
This lesson discusses how to use a Mainform + Subforms in Microsoft Access to find and enter data for payments on orders. The sample data comes from a custom shop that builds and sells movable storage structures that are delivered to your property. …
As many of you are aware about Scanpst.exe utility which is owned by Microsoft itself to repair inaccessible or damaged PST files, but the question is do you really think Scanpst.exe is capable to repair all sorts of PST related corruption issues?
Suggested Courses
Course of the Month16 days, 12 hours left to enroll

862 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question