Sorting Hashtable by Order in Which It Was Created - c#

This is similar to How to keep the order of elements in hashtable, except for .NET.
Is there any Hashtable or Dictionary in .NET that allows you to access it's .Index property for the entry in the order in which it was added to the collection?

A NameValueCollection can retrieve elements by index (but you cannot ask for the index of a specific key or element). So,
var coll = new NameValueCollection();
coll.Add("Z", "1");
coll.Add("A", "2");
Console.WriteLine("{0} = {1}", coll.GetKey(0), coll[0]); // prints "Z = 1"
However, it behaves oddly (compared to an IDictionary) when you add a key multiple times:
var coll = new NameValueCollection();
coll.Add("Z", "1");
coll.Add("A", "2");
coll.Add("Z", "3");
Console.WriteLine(coll[0]); // prints "1,3"
The behaviour is well documented, however.
Caution: NameValueCollection does not implement IDictionary.
As an aside: Dictionary<K,V> does not have any index you can use, but as long as you only add elements, and never remove any, the order of the elements is the insertion order. Note that this is a detail of Microsoft's current implementation: the documentation explicitly states that the order is random, so this behavior can change in future versions of the .NET Framework or Mono.

If this is something that you need to keep track of efficiently, then you are using the wrong data structure. Instead, you should use a SortedDictionary where the key is tagged with the index of when it was added (or a timestamp) and a custom IComparer that compares two keys based on the index (or the timestamp).

You can use a separate list to store the elements in the order they are added. Something along the lines of the following sample:
public class ListedDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
List<TValue> _list = new List<TValue>();
Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey,TValue>();
public IEnumerable<TValue> ListedValues
{
get { return _list; }
}
public void Add(TKey key, TValue value)
{
_dictionary.Add(key, value);
_list.Add(value);
}
public bool ContainsKey(TKey key)
{
return _dictionary.ContainsKey(key);
}
public ICollection<TKey> Keys { get { return _dictionary.Keys; } }
public bool Remove(TKey key)
{
_list.Remove(_dictionary[key]);
return _dictionary.Remove(key);
}
// further interface methods...
}

Is there any Hashtable or Dictionary in .NET that allows you to access it's .Index property for the entry in the order in which it was added to the collection?
No. You can enumerate over all the items in a Hastable or Dictionary, but these are not guaranteed to be in any sort of order (most likely they are not)
You would have to either use a different data structure altogether, (such as SortedDictionary or SortedList) or use a separate list to store the order in which they were added. You would want to wrap the ordered list and your dictionary/hashtable in another class to keep them synched.

Take a look at the OrderedDictionary class. Not only can you access it via keys, but also via an index (position).

An alternative is to create an array of stuctures, so instead of using
dictionary.Add{"key1","value1"}
you create a structure with the key/value like:
public struct myStruct{
private string _sKey;
public string sKey{
get { return _sKey; }
set { _sKey = value; }
}
private string _sValue;
public string sValue {
get { return _sValue; }
set { _sValue = value; }
}
}
// create list here
List<myStruct> myList = new List<myStruct>();
// create an instance of the structure to add to the list
myStruct item = new myStruct();
item.sKey = "key1";
item.sValue = "value1";
// then add the structure to the list
myList.Add(item);
Using this method you can add extra dimensions to the list without too much effort, just add a new member in the struct.
Note, if you need to modify items in the list after they have been added you will have to change the struct into a class. See this page for more info on this issue: error changing value of structure in a list

Related

Use HashSet as Dictionary Key - Compare all elements

I am checking if a total group of edges already contains the connection between 2 points.
I want to use HashSet's that will contain 2 vectors as Dictionary keys. Then I want to be able to call a performant Dictionary.ContainsKey(hashSet). I want the contains/equality check to be dependent on the Vectors in the Set.
Fex. If I add HashSet [V000 V001] to the Dict. I want to get Dictionary.ContainsKey(HashSet [V001 V000]) return true. (HashSet, so the order can vary, just the same Elements)
The Problem seems to be, that the Dictionary.ContainsKey() method does see separately created HashSets as different objects, even though, they contain the same elements.
Dictionary<HashSet<Vector3>, Vector3> d = new Dictionary<HashSet<Vector3>, Vector3>();
HashSet<Vector3> s = new HashSet<Vector3>();
s.Add(Vector3.one);
s.Add(Vector3.zero);
d.Add(s);
HashSet<Vector3> s2 = new HashSet<Vector3>();
s2.Add(Vector3.zero);
s2.Add(Vector3.one);
bool doesContain = d.ContainsKey(s2); // should be true
You also may suggest a better way of doing this 'Contains()' check efficiently.
The HashSet type doesn't do the equality comparison you want out of the box. It only has reference equality.
To get what you want, you'll need a new type to use as the Dictionary key. The new type will have a HashSet property, and overload Equals() and GetHashCode(), and may as well implement IEquatable at this point as well.
I'll get you started:
public class HashKey<T> : IEquatable<HashKey<T>>
{
private HashSet<T> _items;
public HashSet<T> Items
{
get {return _items;}
private set {_items = value;}
}
public HashKey()
{
_items = new HashSet<T>();
}
public HashKey(HashSet<T> initialSet)
{
_items = initialSet ?? new HashSet();
}
public override int GetHashCode()
{
// I'm leaving this for you to do
}
public override bool Equals(Object obj)
{
if (! (obj is HashKey)) return false;
return this.GetHashCode().Equals(obj.GetHashCode());
}
public bool Equals(HashSet<T> obj)
{
if (obj is null) return false;
return this.GetHashCode().Equals(obj.GetHashCode());
}
}
You want to use a hashset as key.
So the keys are references where one key is one hashset reference.
The ContainsKey compare references.
For what you want to do, you can create a class that implements IEqualityComparer to pass it to the dictionary constructor.
https://learn.microsoft.com/dotnet/api/system.collections.generic.iequalitycomparer-1
If you want a full management, you should create a new class embedding the dictionary and implement your own public operations wrapping that of the dictionary : ContainsKey and all others methods you need.
public class MyDictionary : IEnumerable<>
{
private Dictionary<HashSet<Vector3>, Vector3> d
= new Dictionary<HashSet<Vector3>, Vector3>();
public int Count { get; }
public this...
public ContainsKey()
{
// implements your own comparison algorithm
}
public Add();
public Remove();
...
}
So you will have a strongly typed dictionary for your intended usage.

Keep the most recent KeyValuePairs in a SortedList

I have a SortedList that adds KeyValuePairs every 10 min. I'm trying to keep the most recent 10 KeyValuePairs and remove all prior pairs but what I'm doing isn't working. Below I attached my code with explanation along each step. Any help is greatly appreciated.
private SortedList<int, double> myList = new SortedList<int, double>();
// Every 10 minutes a new KeyValuePair is added to myList so
// I have no issue with sorting. I'm only trying to get the most
// recent 10 KeyValuePairs.
// My Attempt (the only one that worked without errors)
int mylistCount = 10;
if (myList.Count()>mylistCount)
{myList.Clear();}
// The issue with my attempt is that it erases the entire myList
// As a result, whenever myList reaches 10, it goes back to Zero.
// What I'm trying to do is keep myList Count at 10 containing only
// the most recent KeyValuePairs.
**
In myList, the Key int is PlayerID# (which is random) and the Value is that Player's Score %
To answer your questions:
Sorting is not an issue with the current set up.
It does not have to be a SortedList, I'm open to any suggestion. I'm just more familiar with using Dictionaries and Lists.
I have never used a Queue but open to trying it. (Will have to research that, I'm learning something new everyday)
There are no time stamps and the timing of new entries is not important. All I'm trying to do is make sure that myList only has the most recent 10.
What I'm trying to do is keep myList Count at 10 containing only the
most recent KeyValuePairs.
You're wanting to keep the 10 most recent pairs so I assume the sorting is by addition time. If that's true, you don't need to have them sorted and thus do not need a SortedList. You could use a Queue as suggested in a comment.
A queue is first in, first out (FIFO). That means you know the first element in the queue is the oldest and the one you need to dequeue when the eleventh element comes in. For example, couldn't this do the trick with little ceremony?
// q is a Queue (FIFO)
if (q.Count == 10)
{
// we've reached our cap, remove the element at the
// front of the q (the oldest one)
q.Dequeue();
}
// we'll always add the newest element to the end of the q
q.Enqueue(new KeyValuePair<int, double>(key, value));
How about using a LinkedList instead of a SortedList.
if(myLinkedList.Count() > 10)
myLinkedList.RemoveFirst();
This will always remove the first added item of the list.
Without knowing much about the key, I offer a simple solution:
Create a class to represent the value as well as the time it was added and implements the IComparable<T> interface:
public class TimeStampedDouble : IComparable<TimeStampedDouble>
{
public TimeStampedDouble(double value)
{
Value = value;
Date = DateTime.Now;
}
public double Value { get; private set; }
public DateTime Date { get; private set; }
public int CompareTo(TimeStampedDouble other)
{
return this.Date.CompareTo(other.Date);
}
// User-defined conversion to double, for convenience
public static implicit operator double(TimeStampedDouble d)
{
return d.Value;
}
}
Change your list to store this type instead:
SortedList<int, TimeStampedDouble> list = new SortedList<int, TimeStampedDouble>();
Add items to the list using the new class:
//In this line, 1 is the key, 6 is the double you are storing.
myList.Add(1, new TimeStampedDouble(6));
myList.Add(3, new TimeStampedDouble(5));
myList.Add(2, new TimeStampedDouble(4));
myList.Add(7, new TimeStampedDouble(3));
myList.Add(5, new TimeStampedDouble(2));
You can now get the oldest item using Linq and remove it:
if (myList.Count() > mylistCount)
{
var oldest = myList.OrderByDescending(i => i.Value).FirstOrDefault();
myList.Remove(oldest.Key);
}
Item with key 5 is removed.
It is not necessary to check if oldest is null because a) it's a value type and b) a check is made for a minimum number of items so the assumption is that the list will always have at least one item, provided mylistCount is greater than 0.
Because an implicit conversion to double is provided, you can use the value without explicit casting:
double doubleValue = myList[7];
I think that the most convenient solution would be to use a bounded list, to ensure that the elements in the list will never exceed the maximum count. Implementing such a list is not very difficult. Probably the most flexible way is to implement the IDictionary<TKey, TValue> interface, delegating the work to an internal SortedList<TKey, TValue>. Bellow is an inheritance-based approach, that requires less code. Every time an added element causes the Count to become larger than the boundedCapacity, the oldest element in the list is automatically removed.
public class BoundedSortedList<TKey, TValue> : SortedList<TKey, TValue>
{
private readonly int _boundedCapacity;
private readonly List<TKey> _queue = new List<TKey>();
public BoundedSortedList(int boundedCapacity)
{
_boundedCapacity = boundedCapacity;
}
public new void Add(TKey key, TValue value)
{
base.Add(key, value);
_queue.Add(key);
if (this.Count > _boundedCapacity)
{
var keyToRemove = _queue[0];
this.Remove(keyToRemove);
}
}
public new TValue this[TKey key]
{
get { return base[key]; }
set { this.Remove(key); this.Add(key, value); }
}
public new bool Remove(TKey key) { _queue.Remove(key); return base.Remove(key); }
public new bool RemoveAt(int index) => throw new NotImplementedException();
public new void Clear() { base.Clear(); _queue.Clear(); }
}
Usage example:
var myList = new BoundedSortedList<int, double>(10);
Incorrect usage example:
var myIList = (IDictionary<int, double>)myList;
This will not work because accessing the class through the interface will bypass the logic that makes the list bounded.
Here is what worked for me:
if (myList.Count()>mylistCount)
{myList.Remove(myList.FirstOrDefault());}
Thank you all

Is there an easy way to have a dictionary-like object that cannot be added to, but whose values can be modified?

Suppose I have a class Composite that is constructed from a dictionary of instruments and weights.
public IReadOnlyDictionary<Instrument, double> Underlyings{ get; private set; }
public Composite(
Id id,
Currency currency,
Dictionary<Instrument, double> underlyings
)
{
Underlyings= underlyings;
}
}
This class is exposed to the client, and I want the client to be able to modify the existing keys' values within Underlyings, but not add new key-value pairs to Underlyings.
Then making Underlyings a ReadOnlyDictionary will not work as the client code will not be able to modify the values for existing keys. So my solution was to take the wrapper around a dictionary from this answer and modify the setter for TValue IDictionary<TKey, TValue>.this[TKey key] such that existing values can be modified. But this seems like a silly solution - is there an easier way than writing a wrapper class to have a dictionary which has modifiable existing key-value pairs, but cannot have new key-value pairs added to it? Apologies for the very simplistic question.
No, there is no standard dictionary that only allows updates. Its all or nothing.
As you have discovered, you have to create it your own, or find an implementation that is already there. Overriding the Add and this[] property is a solution that might work for you.
You can use ReadOnlyDictionary, but provide another method to modify value of given key. Something like:
Dictionary<KeyType, ValueType> _dictionary;
public ReadOnlyDictionary<KeyType, ValueType> Dictionary => new ReadOnlyDictionary<KeyType, ValueType>(_dictionary);
public void ChangeValue(KeyType key, ValueType value) => _dictionary[key].Value = value;
As you said, create a wrapper over a dictionary or inherit from the dictionary class an override Add.
Not a good way but a hack.
Generate a wrapper around your data and Use a ReadOnlyDictionary which is introduced in .NET 4.5.
class MyDataWrapper<T>
{
public T Data { set; get; }
}
var dicData = new Dictionary<int, MyDataWrapper<string>>();
dicData[0] = new MyDataWrapper<string> { Data = "0" };
dicData[1] = new MyDataWrapper<string> { Data = "0" };
var myDic = new ReadOnlyDictionary<int, MyDataWrapper<string>>(dic);
myDic[1].Data = "2";
// myDic[1] = new ... compile error
// myDic.Add() compile error

looking for an appropriate data structure(preferably Dictionary and List) for this scenario

In a method call an object is getting passed it.
From this object I can get two things: an ItemData propery and a Row property so for example:
oPTL.ItemData, oPTL.Row
I want to have a data structure that each time this method is called it can update this data structure so for example one time oPTL.ItemData is "Spread1" and oPTL.Row is 2 so we should be able to save that Spread1 has value 2...next call for example we should be able to save "Spread3" has value 3..next call "Spread1" has ALSO value 4 , etc...
So it is like a Dictionary<String,<List>> but still I have problem with declaring and using it this way in the code, any code sample you can help me with?
You can use a dictionary where the values are Lists:
IDictionary<string, List<int>> rows = new Dictionary<string, List<int>>();
To populate it you can use this extension method:
public static class DictionaryDefaultExtension
{
public static TValue GetOrDefault<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary,
TKey key,
Func<TValue> defaultValue)
{
TValue result;
if (dictionary.TryGetValue(key, out result))
{
return result;
}
else
{
TValue value = defaultValue();
dictionary[key] = value;
return value;
}
}
}
Use like this:
d.GetOrDefault(oPTL.ItemData, () => new List<int>()).Add(oPTL.Row);
What you're looking for is Dictionary<string, List<int>> - assuming your .ItemData and .Row properties are in fact string and int respectively.
When you read item with "Spread1" value, you first check whether such key already exists in dictionary by calling .ContainsKey(string) method. If so, you add new Row value - if not, you create new key with brand new list, like in example below:
var myItems = new Dictionary<string, List<int>>();
// ...
if (myItems.ContainsKey(newItem.ItemData))
{
// myItems[newItem.ItemData] actually contains List<int> we created at some
// point in the other part of if-else.
// The .Add method we call here belongs to List
List<int> itemValues = myItems[newItem.ItemData];
itemValues.Add(newItem.Row);
}
else
{
myItems.Add(newItem.ItemData, new List<int> { newItem.Row });
}
Edited to add clarification with two .Add methods.

Is there a Dictionary<string, object> collection which allows multiple keys?

I currently have a menu with subitems that is being stored in this dictionary variable:
private Dictionary<string, UserControl> _leftSubMenuItems
= new Dictionary<string, UserControl>();
So I add views to the e.g. the "Customer" section like this:
_leftSubMenuItems.Add("customers", container.Resolve<EditCustomer>());
_leftSubMenuItems.Add("customers", container.Resolve<CustomerReports>());
But since I am using a Dictionary, I can only have one key named "customers".
My natural tendency would be to now create a custom struct with properties "Section" and "View", but is there a .NET collection is better suited for this task, something like a "MultiKeyDictionary"?
ANSWER:
Thanks maciejkow, I expanded your suggestion to get exactly what I needed:
using System;
using System.Collections.Generic;
namespace TestMultiValueDictionary
{
class Program
{
static void Main(string[] args)
{
MultiValueDictionary<string, object> leftSubMenuItems = new MultiValueDictionary<string, object>();
leftSubMenuItems.Add("customers", "customers-view1");
leftSubMenuItems.Add("customers", "customers-view2");
leftSubMenuItems.Add("customers", "customers-view3");
leftSubMenuItems.Add("employees", "employees-view1");
leftSubMenuItems.Add("employees", "employees-view2");
foreach (var leftSubMenuItem in leftSubMenuItems.GetValues("customers"))
{
Console.WriteLine(leftSubMenuItem);
}
Console.WriteLine("---");
foreach (var leftSubMenuItem in leftSubMenuItems.GetAllValues())
{
Console.WriteLine(leftSubMenuItem);
}
Console.ReadLine();
}
}
public class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
if (!ContainsKey(key))
Add(key, new List<TValue>());
this[key].Add(value);
}
public List<TValue> GetValues(TKey key)
{
return this[key];
}
public List<TValue> GetAllValues()
{
List<TValue> list = new List<TValue>();
foreach (TKey key in this.Keys)
{
List<TValue> values = this.GetValues(key);
list.AddRange(values);
}
return list;
}
}
}
Answer 2:
Thanks Blixt for the tip about yield, here is GetAllValues with that change:
public IEnumerable<TValue> GetAllValues()
{
foreach (TKey key in this.Keys)
{
List<TValue> values = this.GetValuesForKey(key);
foreach (var value in values)
{
yield return value;
}
}
}
Answer 2 refactored further:
Here is a much more succinct way to do the same thing, thanks Keith:
public IEnumerable<TValue> GetAllValues()
{
foreach (var keyValPair in this)
foreach (var val in keyValPair.Value)
yield return val;
}
If you need variable number of values for one key, why not create Dictionary<string, List<UserControl>> ? Furthermore, you could inherit this class and create your own Add, get same syntax you're using now. This way you can avoid manual adding of empty lists before adding new control.
sth like this:
class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
if(!ContainsKey(key))
Add(key, new List<TValue>());
this[key].Add(value);
}
}
Check out NGenerics' HashList. It's a Dictionary which maintains a list of values for each key. Wintellect's PowerCollections library also has a handy MultiDictionary class which does things like automatically clean up when you remove the last value associated with a given key.
How about making the container value type a list:
private Dictionary<string, List<UserControl>> _leftSubMenuItems =
new Dictionary<string, List<UserControl>>();
if (!_leftSubMenuItems.ContainsKey("customers"))
{
_leftSubMenuItems["customers"] = new List<UserControl>();
}
_leftSubMenuItems["customers"].Add(container.Resolve<EditCustomer>());
_leftSubMenuItems["customers"].Add(container.Resolve<CustomerReports>());
Just a few tweaks...
public class MultiValueDictionary<TKey, TValue> :
Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
List<TValue> valList;
//a single TryGetValue is quicker than Contains then []
if (this.TryGetValue(key, out valList))
valList.Add(value);
else
this.Add( key, new List<TValue> { value } );
}
//this can be simplified using yield
public IEnumerable<TValue> GetAllValues()
{
//dictionaries are already IEnumerable, you don't need the extra lookup
foreach (var keyValPair in this)
foreach(var val in keyValPair.Value);
yield return val;
}
}
The .NET framework 3.5 includes a special LINQ Lookup class.
It is similar to a dictionary except that it can handle multiple items with the same key. When you do a search using a given key, instead of receiving a single element, you receive a group of elements that match that key.
I read that it is a hashtable under the covers so it is fast for retrieving.
You use it something like this:
var example1 = (from element in ListWithDuplicates
select element)
.ToLookup(A => A.Name);
There are a bunch of caveats:
The Lookup class has no public constructor, so you cant just create a Lookup object, it seems to only be available using the .ToLookup syntax.
You cannot edit it once it has been created, no Add or Remove etc.
Apparently its not serializable
Using the grouped data can be a bit tricky
Theres a great article here discussing the Lookup and its implications in more detail.
No, there's no better built-in collection. I think your "natural tendency" is perfectly suited for solving this problem, as those are not really "same keys," but unique keys composed of different parts and Dictionary does the job. You can also nest dictionary (makes sense if you have large number of values for each name):
Dictionary<string, Dictionary<Type, object>> dict = ...;
var value = (T)dict[name][typeof(T)];
This approach will resolve to the element using a single hash table lookup. If you maintain a list of items for each element, you'll have to linearly traverse the list each time you need an element to lookup which defeats the purpose of using a Dictionary in the first place.
I don't know of a "MultiKeyDictionary". I'd recommend using a struct and overriding GetHashCode, Equals and implementing IEquatable<StructName> (which is used by Dictionary<TKey,TValue>).
Are you looking to store multiple entries per key together? Somethign like this ?

Categories

Resources