What is an example of a Hashtable implementation in C#? - c#

I realize C# and .NET in general already has the Hashtable and Dictionary classes.
Can anyone demonstrate in C# an implementation of a Hashtable?
Update: To clarify, I'm not ncessarily looking for a complete implementation, just an example of the core features of a hashtable (i.e. add,remove, find by key).

Long after the question has been asked, so I don't expect to earn much rep. However I decided it would be fun to write my own very basic example (in less than 90 lines of code):
public struct KeyValue<K, V>
{
public K Key { get; set; }
public V Value { get; set; }
}
public class FixedSizeGenericHashTable<K,V>
{
private readonly int size;
private readonly LinkedList<KeyValue<K,V>>[] items;
public FixedSizeGenericHashTable(int size)
{
this.size = size;
items = new LinkedList<KeyValue<K,V>>[size];
}
protected int GetArrayPosition(K key)
{
int position = key.GetHashCode() % size;
return Math.Abs(position);
}
public V Find(K key)
{
int position = GetArrayPosition(key);
LinkedList<KeyValue<K, V>> linkedList = GetLinkedList(position);
foreach (KeyValue<K,V> item in linkedList)
{
if (item.Key.Equals(key))
{
return item.Value;
}
}
return default(V);
}
public void Add(K key, V value)
{
int position = GetArrayPosition(key);
LinkedList<KeyValue<K, V>> linkedList = GetLinkedList(position);
KeyValue<K, V> item = new KeyValue<K, V>() { Key = key, Value = value };
linkedList.AddLast(item);
}
public void Remove(K key)
{
int position = GetArrayPosition(key);
LinkedList<KeyValue<K, V>> linkedList = GetLinkedList(position);
bool itemFound = false;
KeyValue<K, V> foundItem = default(KeyValue<K, V>);
foreach (KeyValue<K,V> item in linkedList)
{
if (item.Key.Equals(key))
{
itemFound = true;
foundItem = item;
}
}
if (itemFound)
{
linkedList.Remove(foundItem);
}
}
protected LinkedList<KeyValue<K, V>> GetLinkedList(int position)
{
LinkedList<KeyValue<K, V>> linkedList = items[position];
if (linkedList == null)
{
linkedList = new LinkedList<KeyValue<K, V>>();
items[position] = linkedList;
}
return linkedList;
}
}
Here's a little test application:
static void Main(string[] args)
{
FixedSizeGenericHashTable<string, string> hash = new FixedSizeGenericHashTable<string, string>(20);
hash.Add("1", "item 1");
hash.Add("2", "item 2");
hash.Add("dsfdsdsd", "sadsadsadsad");
string one = hash.Find("1");
string two = hash.Find("2");
string dsfdsdsd = hash.Find("dsfdsdsd");
hash.Remove("1");
Console.ReadLine();
}
It's not the best implementation, but it works for Add, Remove and Find. It uses chaining and a simple modulo algorithm to find the appropriate bucket.

Have you looked at the C5 collections? You can download the source which includes a hash table.

You can see how the .NET Hashtable is implemented (for example in C#) using reflector
http://www.red-gate.com/products/reflector/

There is also the Mono version of the class libraries of course:
System.Collections.Hashtable
System.Collections.Generic.Dictionary

You could also look at the Hashtable implementation from Mono here:
http://anonsvn.mono-project.com/viewvc/trunk/mcs/class/corlib/System.Collections/Hashtable.cs?revision=111788&view=markup

Related

C# How to make graph objects cloneable

I've got newbie question, problem which I have to solve, to keep moving forward with my Unity project... It's probably pretty easy, but I'm not a programmer and a just don't know how to implement something I need. I checked documentation, but still don't know how to do it :/
I'm using graph class and I need to clone graph objects. Already know it's necessary to write deep clone function, coz I need NO references, just list of independent objects.
What I need is: create list of graphs. Change first one (by adding some edges), and clone it to the 2nd position on the list. Change 2nd (without changing 1st), and clone it to the 3rd position on the list, and so on...
This is my starting point:
public class Graph<T>
{
public int xMatrix;
public int yMatrix;
public int[] vertices;
public Graph() { }
public Graph(IEnumerable<T> vertices, IEnumerable<Tuple<T, T>> edges)
{
foreach (var vertex in vertices)
AddVertex(vertex);
foreach (var edge in edges)
AddEdge(edge);
}
public Dictionary<T, HashSet<T>> AdjacencyList { get; } = new Dictionary<T, HashSet<T>>();
public void AddVertex(T vertex)
{
AdjacencyList[vertex] = new HashSet<T>();
}
public void AddEdge(Tuple<T, T> edge)
{
if (AdjacencyList.ContainsKey(edge.Item1) && AdjacencyList.ContainsKey(edge.Item2))
{
AdjacencyList[edge.Item1].Add(edge.Item2);
AdjacencyList[edge.Item2].Add(edge.Item1);
}
}
}
And what I tried:
public class Graph<T> :ICloneable
{
public int xMatrix;
public int yMatrix;
public int[] vertices;
public IEnumerable<int> verts;
public IEnumerable<Tuple<int, int>> edgs;
public Graph() { }
public Graph(IEnumerable<T> vertices, IEnumerable<Tuple<T, T>> edges)
{
foreach (var vertex in vertices)
AddVertex(vertex);
foreach (var edge in edges)
AddEdge(edge);
verts = (IEnumerable<int>)vertices;
edgs = (IEnumerable<Tuple<int, int>>)edges;
}
public Dictionary<T, HashSet<T>> AdjacencyList { get; set; } = new Dictionary<T, HashSet<T>>();
public void AddVertex(T vertex)
{
AdjacencyList[vertex] = new HashSet<T>();
}
public void AddEdge(Tuple<T, T> edge)
{
if (AdjacencyList.ContainsKey(edge.Item1) && AdjacencyList.ContainsKey(edge.Item2))
{
AdjacencyList[edge.Item1].Add(edge.Item2);
AdjacencyList[edge.Item2].Add(edge.Item1);
}
//this.edgs.Append<edge>;
//IEnumerable<Tuple<int, int>> newEdgs = this.edgs.Append<Tuple<edge.Item1, edge.Item2>;
//IEnumerable<Tuple<int, int>> newEdgs = this.edgs.Append<edge>;
//???
}
public object Clone()
{
IEnumerable<int> vertices = this.verts;
IEnumerable<Tuple<int, int>> edges = this.edgs;
Graph<int> other = new Graph<int>(vertices, edges);
return other;
}
}
Thank you in advance!
For the most part your implementation doesn't have any inherent flaws.
The issue that might arise from the IEnumerables that you are passing around.
When you store an enumerable object, such as an array of integers inside of a IEnumerable variable you aren't copying the values but rather just storing the address(reference) to the original object, unless that object itself is a value type.
If the original type is a reference type, whether mutable or not, such as an array, we can work around this by copying the content of the reference type, for arrays we could use .CopyTo(destinationArray).
Another thing that might mess with you is that Tuple<> unlike ValueTuple or (type,type) is an immutable reference type.
Most of this can be avoided though. If you feel comfortable modifying how you clone the object, you can instead copy AdjacencyList instead.
public class Graph<T>
{
public int xMatrix;
public int yMatrix;
public int[] vertices;
public Dictionary<T, HashSet<T>> AdjacencyList => _AdjacencyList;
protected Dictionary<T, HashSet<T>> _AdjacencyList = new Dictionary<T, HashSet<T>>();
public Graph() { }
public Graph(IEnumerable<T> vertices, IEnumerable<Tuple<T, T>> edges) { }
public void AddVertex(T vertex) { }
public void AddEdge(Tuple<T, T> edge) { }
public object Clone()
{
Graph<T> newGraph = new Graph<T>()
{
yMatrix = this.yMatrix,
xMatrix = this.xMatrix,
vertices = new int[vertices.Length]
};
vertices.CopyTo(newGraph.vertices, 0);
newGraph._AdjacencyList = new Dictionary<T, HashSet<T>>(AdjacencyList.Select(x =>
{
T[] copied = new T[x.Value.Count];
x.Value.CopyTo(copied);
return new KeyValuePair<T, HashSet<T>>(x.Key, new HashSet<T>(copied));
}));
return newGraph;
}
}
So... with some help 'of the Internet' problem is finally solved:
Code from DekuDesu’s answer works great in VS C# console applications with .NET Core 3.1 or .NET 5.0, but Unity engine doesn't support that.
Fix for that is change code to work in VS in C# ClassLibrary (.NET Framework 4.7.1 & Unity settings on .NET 4.x) or (.NET Standard & Unity settings on .NET Standard 2.0).
The ability to construct a new Dictionary<> with an IEnumerable<KeyValuePair> isn't available in .NET Framework. Alternatively I used IEnumerable<>.ToDictionary() and it worked.
This works:
public class Graph<T>
{
public int xMatrix;
public int yMatrix;
public int[] vertices;
public Dictionary<T, HashSet<T>> AdjacencyList => _AdjacencyList;
protected Dictionary<T, HashSet<T>> _AdjacencyList = new Dictionary<T, HashSet<T>>();
public Graph() { }
public Graph(IEnumerable<T> vertices, IEnumerable<Tuple<T, T>> edges)
{
foreach (var vertex in vertices)
AddVertex(vertex);
foreach (var edge in edges)
AddEdge(edge);
}
public void AddVertex(T vertex)
{
AdjacencyList[vertex] = new HashSet<T>();
}
public void AddEdge(Tuple<T, T> edge)
{
if (AdjacencyList.ContainsKey(edge.Item1) && AdjacencyList.ContainsKey(edge.Item2))
{
AdjacencyList[edge.Item1].Add(edge.Item2);
AdjacencyList[edge.Item2].Add(edge.Item1);
}
}
public object Clone()
{
Graph<T> newGraph = new Graph<T>()
{
yMatrix = this.yMatrix,
xMatrix = this.xMatrix,
vertices = new int[vertices.Length]
};
vertices.CopyTo(newGraph.vertices, 0);
newGraph._AdjacencyList = AdjacencyList.Select(x =>
{
T[] copied = new T[x.Value.Count];
x.Value.CopyTo(copied);
return new KeyValuePair<T, HashSet<T>>(x.Key, new HashSet<T>(copied));
}).ToDictionary(o => o.Key, o => o.Value);
return newGraph;
}
}
Thanks for your help!

Quick (sub)string search in large set of data

Given a city:
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public string Country { get; set; }
public LatLong Location { get; set; }
}
I have a list of close to 3,000,000 cities (and towns and villages etc.) in a file. This file is read into memory; I have been playing with arrays, lists, dictionaries (key = Id) etc.
I want to find, as quick as possible, all cities matching a substring (case insensitive). So when I search for 'yor' I want to get all matches (1000+) ASAP (matching 'York Town', 'Villa Mayor', 'New York', ...).
Functionally you could write this as:
cities.Values.Where(c => c.Name.IndexOf("yor", StringComparison.OrdinalIgnoreCase) >= 0)
I don't mind doing some pre-processing when reading the file; as a matter of fact: that's what I'm mostly looking for. Read the file, "chew" on the data creating some sort of index or... and then be ready to answer queries like "yor".
I want this to be standalone, self-contained. I do not want to add dependencies like an RDBMS, ElasticSearch or whatever. I don't mind having (parts of) the list in memory more than once. I don't mind spending some memory on a datastructure to help me find my results quickly. I don't want libraries or packages. I want an algorithm I can implement myself.
Basically I want the above LINQ statement, but optimized for my case; currently plowing through almost 3,000,000 records takes about +/- 2 seconds. I want this sub 0.1 second so I could use the search and it's results as 'autocomplete'.
Creating an "index"(-alike) structure is probably what I need. As I'm writing I remember something about a "bloom filter" but I'm not sure if that would help or even supports substring search. Will look into that now.
Any tips, pointers, help very much appreciated.
I created a bit of a hybrid based on a suffix array / dictionary. Thanks to saibot for suggesting it first and all other people helping and suggesting.
This is what I came up with:
public class CitiesCollection
{
private Dictionary<int, City> _cities;
private SuffixDict<int> _suffixdict;
public CitiesCollection(IEnumerable<City> cities, int minLen)
{
_cities = cities.ToDictionary(c => c.Id);
_suffixdict = new SuffixDict<int>(minLen, _cities.Values.Count);
foreach (var c in _cities.Values)
_suffixdict.Add(c.Name, c.Id);
}
public IEnumerable<City> Find(string find)
{
var normalizedFind = _suffixdict.NormalizeString(find);
foreach (var id in _suffixdict.Get(normalizedFind).Where(v => _cities[v].Name.IndexOf(normalizedFind, StringComparison.OrdinalIgnoreCase) >= 0))
yield return _cities[id];
}
}
public class SuffixDict<T>
{
private readonly int _suffixsize;
private ConcurrentDictionary<string, IList<T>> _dict;
public SuffixDict(int suffixSize, int capacity)
{
_suffixsize = suffixSize;
_dict = new ConcurrentDictionary<string, IList<T>>(Environment.ProcessorCount, capacity);
}
public void Add(string suffix, T value)
{
foreach (var s in GetSuffixes(suffix))
AddDict(s, value);
}
public IEnumerable<T> Get(string suffix)
{
return Find(suffix).Distinct();
}
private IEnumerable<T> Find(string suffix)
{
foreach (var s in GetSuffixes(suffix))
{
if (_dict.TryGetValue(s, out var result))
foreach (var i in result)
yield return i;
}
}
public string NormalizeString(string value)
{
return value.Normalize().ToLowerInvariant();
}
private void AddDict(string suffix, T value)
{
_dict.AddOrUpdate(suffix, (s) => new List<T>() { value }, (k, v) => { v.Add(value); return v; });
}
private IEnumerable<string> GetSuffixes(string value)
{
var nv = NormalizeString(value);
for (var i = 0; i <= nv.Length - _suffixsize ; i++)
yield return nv.Substring(i, _suffixsize);
}
}
Usage (where I assume mycities to be an IEnumerable<City> with the given City object from the question):
var cc = new CitiesCollection(mycities, 3);
var results = cc.Find("york");
Some results:
Find: sterda elapsed: 00:00:00.0220522 results: 32
Find: york elapsed: 00:00:00.0006212 results: 155
Find: dorf elapsed: 00:00:00.0086439 results: 6095
Memory usage is very, very acceptable. Only 650MB total having the entire collection of 3,000,000 cities in memory.
In the above I'm storing Id's in the "SuffixDict" and I have a level of indirection (dictionary lookups to find id=>city). This can be further simplified to:
public class CitiesCollection
{
private SuffixDict<City> _suffixdict;
public CitiesCollection(IEnumerable<City> cities, int minLen, int capacity = 1000)
{
_suffixdict = new SuffixDict<City>(minLen, capacity);
foreach (var c in cities)
_suffixdict.Add(c.Name, c);
}
public IEnumerable<City> Find(string find, StringComparison stringComparison = StringComparison.OrdinalIgnoreCase)
{
var normalizedFind = SuffixDict<City>.NormalizeString(find);
var x = _suffixdict.Find(normalizedFind).ToArray();
foreach (var city in _suffixdict.Find(normalizedFind).Where(v => v.Name.IndexOf(normalizedFind, stringComparison) >= 0))
yield return city;
}
}
public class SuffixDict<T>
{
private readonly int _suffixsize;
private ConcurrentDictionary<string, IList<T>> _dict;
public SuffixDict(int suffixSize, int capacity = 1000)
{
_suffixsize = suffixSize;
_dict = new ConcurrentDictionary<string, IList<T>>(Environment.ProcessorCount, capacity);
}
public void Add(string suffix, T value)
{
foreach (var s in GetSuffixes(suffix, _suffixsize))
AddDict(s, value);
}
public IEnumerable<T> Find(string suffix)
{
var normalizedfind = NormalizeString(suffix);
var find = normalizedfind.Substring(0, Math.Min(normalizedfind.Length, _suffixsize));
if (_dict.TryGetValue(find, out var result))
foreach (var i in result)
yield return i;
}
private void AddDict(string suffix, T value)
{
_dict.AddOrUpdate(suffix, (s) => new List<T>() { value }, (k, v) => { v.Add(value); return v; });
}
public static string NormalizeString(string value)
{
return value.Normalize().ToLowerInvariant();
}
private static IEnumerable<string> GetSuffixes(string value, int suffixSize)
{
var nv = NormalizeString(value);
if (value.Length < suffixSize)
{
yield return nv;
}
else
{
for (var i = 0; i <= nv.Length - suffixSize; i++)
yield return nv.Substring(i, suffixSize);
}
}
}
This bumps the load time up from 00:00:16.3899085 to 00:00:25.6113214, memory usage goes down from 650MB to 486MB. Lookups/searches perform a bit better since we have one less level of indirection.
Find: sterda elapsed: 00:00:00.0168616 results: 32
Find: york elapsed: 00:00:00.0003945 results: 155
Find: dorf elapsed: 00:00:00.0062015 results: 6095
I'm happy with the results so far. I'll do a little polishing and refactoring and call it a day! Thanks everybody for the help!
And this is how it performs with 2,972,036 cities:
This has evolved into a case-insensitive, accent-insensitive search by modifying the code to this:
public static class ExtensionMethods
{
public static T FirstOrDefault<T>(this IEnumerable<T> src, Func<T, bool> testFn, T defval)
{
return src.Where(aT => testFn(aT)).DefaultIfEmpty(defval).First();
}
public static int IndexOf(this string source, string match, IEqualityComparer<string> sc)
{
return Enumerable.Range(0, source.Length) // for each position in the string
.FirstOrDefault(i => // find the first position where either
// match is Equals at this position for length of match (or to end of string) or
sc.Equals(source.Substring(i, Math.Min(match.Length, source.Length - i)), match) ||
// match is Equals to on of the substrings beginning at this position
Enumerable.Range(1, source.Length - i - 1).Any(ml => sc.Equals(source.Substring(i, ml), match)),
-1 // else return -1 if no position matches
);
}
}
public class CaseAccentInsensitiveEqualityComparer : IEqualityComparer<string>
{
private static readonly CompareOptions _compareoptions = CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreSymbols;
private static readonly CultureInfo _cultureinfo = CultureInfo.InvariantCulture;
public bool Equals(string x, string y)
{
return string.Compare(x, y, _cultureinfo, _compareoptions) == 0;
}
public int GetHashCode(string obj)
{
return obj != null ? RemoveDiacritics(obj).ToUpperInvariant().GetHashCode() : 0;
}
private string RemoveDiacritics(string text)
{
return string.Concat(
text.Normalize(NormalizationForm.FormD)
.Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark)
).Normalize(NormalizationForm.FormC);
}
}
public class CitiesCollection
{
private SuffixDict<City> _suffixdict;
private HashSet<string> _countries;
private Dictionary<int, City> _cities;
private readonly IEqualityComparer<string> _comparer = new CaseAccentInsensitiveEqualityComparer();
public CitiesCollection(IEnumerable<City> cities, int minLen, int capacity = 1000)
{
_suffixdict = new SuffixDict<City>(minLen, _comparer, capacity);
_countries = new HashSet<string>();
_cities = new Dictionary<int, City>(capacity);
foreach (var c in cities)
{
_suffixdict.Add(c.Name, c);
_countries.Add(c.Country);
_cities.Add(c.Id, c);
}
}
public City this[int index] => _cities[index];
public IEnumerable<string> Countries => _countries;
public IEnumerable<City> Find(string find, StringComparison stringComparison = StringComparison.OrdinalIgnoreCase)
{
foreach (var city in _suffixdict.Find(find).Where(v => v.Name.IndexOf(find, _comparer) >= 0))
yield return city;
}
}
public class SuffixDict<T>
{
private readonly int _suffixsize;
private ConcurrentDictionary<string, IList<T>> _dict;
public SuffixDict(int suffixSize, IEqualityComparer<string> stringComparer, int capacity = 1000)
{
_suffixsize = suffixSize;
_dict = new ConcurrentDictionary<string, IList<T>>(Environment.ProcessorCount, capacity, stringComparer);
}
public void Add(string suffix, T value)
{
foreach (var s in GetSuffixes(suffix, _suffixsize))
AddDict(s, value);
}
public IEnumerable<T> Find(string suffix)
{
var find = suffix.Substring(0, Math.Min(suffix.Length, _suffixsize));
if (_dict.TryGetValue(find, out var result))
{
foreach (var i in result)
yield return i;
}
}
private void AddDict(string suffix, T value)
{
_dict.AddOrUpdate(suffix, (s) => new List<T>() { value }, (k, v) => { v.Add(value); return v; });
}
private static IEnumerable<string> GetSuffixes(string value, int suffixSize)
{
if (value.Length < 2)
{
yield return value;
}
else
{
for (var i = 0; i <= value.Length - suffixSize; i++)
yield return value.Substring(i, suffixSize);
}
}
}
With credit also to Netmage and Mitsugui. There are still some issues / edge-cases but it's continually improving!
You could use a suffix tree: https://en.wikipedia.org/wiki/Suffix_tree
It requires enough space to store about 20 times your list of words in memory
Suffix array is a space efficient alternative: https://en.wikipedia.org/wiki/Suffix_array
in query benchmark contains very faster then indexOf >0
cities.Values.Where(c => c.Name.Contans("yor"))

c# Dictionary<object, T> lookup value

Not sure how to best phrase this which is probably why I'm having difficulty looking it up. Here is a sample console application to demonstrate my meaning.
class Program
{
static void Main(string[] args)
{
var item1 = new Item("Number");
var item2 = new Item("Number");
var dict = new Dictionary<Item, string>();
dict.Add(item1, "Value");
Console.WriteLine(dict.ContainsKey(item2));
var dict2 = new Dictionary<string, string>();
dict2.Add("Number", "Value");
Console.WriteLine(dict2.ContainsKey("Number"));
Console.Read();
}
class Item
{
readonly string number;
public Item(string number)
{
this.number = number;
}
}
}
In this example dict.ContainsKey(item2) returns false and dict2.ContainsKey("Number") returns true. Can Item be defined in such a way that it would behave like a string? The best I can come up with is
static void Main(string[] args)
{
var item1 = new Item("Number");
var item2 = new Item("Number");
var dict = new Dictionary<string, string>();
dict.Add(item1.ToString(), "Test");
Console.WriteLine(dict.ContainsKey(item2.ToString()));
Console.Read();
}
class Item
{
readonly string number;
public Item(string number)
{
this.number = number;
}
public override string ToString()
{
return number;
}
}
This example is contrived, Item would have more fields and ToString() would joint them all up.
You need to override Equals and GetHashCode. Dictionary use Equals and GetHashCode method to compare keys for equality.
class Item
{
readonly string number;
public Item(string number)
{
this.number = number;
}
public override bool Equals(object obj)
{
return Equals(obj as Item);
}
public override int GetHashCode()
{
// this is c# 6 feature
return number?.GetHashCode() ?? 0;
// If you are not using c# 6, you can use
// return number == null ? 0 : number.GetHashCode();
}
private bool Equals(Item another)
{
if (another == null)
return false;
return number == another.number;
}
}
If you have more than one field, you need to account all fields in the Equals and GetHashCode method.

Automatic dictionary key?

I kept googling for some time, and I found that the best way that enables you to have a list containing variables with a corresponding unique key is a HashTable or a Dictionary, but I didn't find anything that enables you to have automatic keys(of type integer). I want to call a function that adds an object(passed as a parameter) to the dictionary and returns the automatically generated key(int), and without any key duplicates. How could I accomplish this? I am completely struggling!
EDIT: To clarify things up. This is a server, and I want to assign a unique key for each client. If I use the maximum key value, this value will soon get to the int maximum value on large servers. Because if a client connects then disconnects he leaves behind an unused value which should be reused in order to avoid reaching a very high key maximum value.
The following should do and it reuses freed up keys:
internal class AutoKeyDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
{
private readonly Dictionary<TKey, TValue> inner;
private readonly Func<TKey, TKey> incrementor;
private readonly Stack<TKey> freeKeys;
private readonly TKey keySeed;
private TKey currentKey;
public AutoKeyDictionary(TKey keySeed, Func<TKey, TKey> incrementor)
{
if (keySeed == null)
throw new ArgumentNullException("keySeed");
if (incrementor == null)
throw new ArgumentNullException("incrementor");
inner = new Dictionary<TKey, TValue>();
freeKeys = new Stack<TKey>();
currentKey = keySeed;
}
public TKey Add(TValue value) //returns the used key
{
TKey usedKey;
if (freeKeys.Count > 0)
{
usedKey = freeKeys.Pop();
inner.Add(usedKey, value);
}
else
{
usedKey = currentKey;
inner.Add(usedKey, value);
currentKey = incrementor(currentKey);
}
return usedKey;
}
public void Clear()
{
inner.Clear();
freeKeys.Clear();
currentKey = keySeed;
}
public bool Remove(TKey key)
{
if (inner.Remove(key))
{
if (inner.Count > 0)
{
freeKeys.Push(key);
}
else
{
freeKeys.Clear();
currentKey = keySeed;
}
return true;
}
return false;
}
public bool TryGetValue(TKey key, out TValue value) { return inner.TryGetValue(key, out value); }
public TValue this[TKey key] { get {return inner[key];} set{inner[key] = value;} }
public bool ContainsKey(TKey key) { return inner.ContainsKey(key); }
public bool ContainsValue(TValue value) { return inner.ContainsValue (value); }
public int Count { get{ return inner.Count; } }
public Dictionary<TKey,TValue>.KeyCollection Keys { get { return inner.Keys; } }
public Dictionary<TKey, TValue>.ValueCollection Values { get { return inner.Values; } }
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return inner.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)inner).GetEnumerator(); }
}
Disclaimer: I haven't tested this code, it could have a few pesty bugs of little importance, the general approach is sound.
Write a class which does this. Something like this:
class AutoIndexDictionary : IEnumerable<Whatever>
{
private readonly Dictionary<int, Whatever> myDict = new Dictionary<int, Whatever>();
private int currentIndex = 0;
public int Add(Whatever item)
{
var myIndex = currentIndex
myDict.Add(myIndex, item);
currentIndex ++;
return myIndex;
}
public void Remove(int index)
{
myDict.Remove(index);
}
// implement IEnumerable, indexer etc.
// ...
}
Create a method that gets the max key value from the dictionary using LINQ, adds 1 to it and then uses that as the key for the value you would like to add, like this:
public void AddToMyDictionary(string value)
{
int NextKey = MyDictionary.Keys.Max() + 1;
MyDictionary.Add(NextKey, value);
}
Obviously, this assumes your dictionary is a Dictionary<int, string>, but you can obviously modify for your purposes.
If you want to re-use keys that have been removed, store the next index when something is added / removed.
private int NextKey = 0;
public int AddToMyDictionary(string value)
{
int currentKey = NextKey;
MyDictionary.Add(currentKey, value);
NextKey = MyDictionary.Keys.Max() + 1;
return currentKey;
}
public void RemoveFromMyDictionary(int key)
{
MyDictionary.Remove(key);
NextKey = key;
}
This is what int Object.GetHashCode() is for.
Wouldn't a List do what you say, without any additional overhead? You call it a "unique integer key", but in List terminology, that's simply called an "index".
If you really wanted a custom function to add a value and get a key all in one step, you could inherit from List<T>, like so:
class MyCustomList<T> : List<T>
{
//Not thread-safe
public int AddAndGetKey(T valueToAdd)
{
Add(valueToAdd);
return LastIndexOf(valueToAdd);
}
}
I use LastIndexOf() because the list may include duplicate values and adding to the list always adds to the end. So this should work unless you get into multithreaded situations where you'd have to add-and-get-index in one atomic operation. (Alternately maybe you could add an extension method to List<T>.)
The advantage of using a List is that there would be no gaps in keys. On the flipside, removing an item in the middle would change the key of every item after it. But I guess it depends what behavior you're looking for.
Given the additional information provided in your edit then i don't think int is the correct datatype for you, you shouldn't reuse ID's the way you are describing as if a client with an ID gets disconnected but don't realise then you could have 1 ID in use by 2 clients. change your datatype to Guid then when you get a new client give it a key of Guid.NewGuid() and the chance of duplicate keys drops as close as possible to 0
I like Stefan Steinegger's solution. Here is an alternative that uses a List<> behind the scenes, but ensures the List<> is never removed from:
class AutoKeyDictionary<TValue> : IEnumerable<TValue> where TValue : class
{
readonly List<TValue> list = new List<TValue>();
public int Add(TValue val)
{
if (val == null)
throw new ArgumentNullException(nameof(val), "This collection will not allow null values.");
list.Add(val);
return list.Count - 1;
}
public void RemoveAt(int key)
{
// do not remove ('list.Count' must never decrease), overwrite with null
// (consider throwing if key was already removed)
list[key] = null;
}
public TValue this[int key]
{
get
{
var val = list[key];
if (val == null)
throw new ArgumentOutOfRangeException(nameof(key), "The value with that key is no longer in this collection.");
return val;
}
}
public int NextKey => list.Count;
public int Count => list.Count(v => v != null); // expensive O(n), Linq
public bool ContainsKey(int key) => key >= 0 && key < list.Count && list[key] != null;
public TValue TryGetValue(int key) => (key >= 0 && key < list.Count) ? list[key] : null;
public void Clear()
{
for (var i = 0; i < list.Count; ++i)
list[i] = null;
}
public IEnumerator<TValue> GetEnumerator() => list.Where(v => v != null).GetEnumerator(); // Linq
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public int FirstKeyOf(TValue val) => list.IndexOf(val);
public IDictionary<int, TValue> ToDictionary()
{
var retColl = new SortedList<int, TValue>(list.Count);
for (var i = 0; i < list.Count; ++i)
{
var val = list[i];
if (val != null)
retColl.Add(i, val);
}
return retColl;
}
// and so on...
}
Not thread-safe, obviously.
Be aware, the same value can be present several times in the collection, but with different keys.

Class<type> in C#

I have a class and want to work with it as Lists: e.g. List<int>, List<string>, ... , List<T>
I have a class Randomizor which will take the collection data type that will be shuffled. How can I do so?
class Randomizor<T>
{
public Randomizor()
{
}
public Array Shuffle(Array toShuffle)
{
}
}
Create a generic class like so:
class Randomizer<TList, TType> where TList : IList<TType>
{
public TList Randomize(TList list)
{
// ...
}
}
Or like so:
class Randomizer<T>
{
public IList<T> Randomize(IList<T> list)
{
// ...
}
}
Not very clear question... do you mean something like this?
public static class Randomizer<T>
{
public static T GetRandom(List<T> list)
{
T value = default(T);
// Perform some random logic.
return value;
}
}
EDIT: I found two superior impementations after a little digging so I would suggest those in preference.
An extension method for this purpose and already been suggested previously here
I include the code paraphrased to Shuffle below.
public static IEnumerable<T> Shuffle<T> (this IEnumerable<T> source)
{
Random random = new Random ();
T [] copy = source.ToArray ();
for (int i = copy.Length - 1; i >= 0; i--)
{
int index = random.Next (i + 1);
yield return copy [index];
copy [index] = copy [i];
}
}
And an interesting solution adapted from this linq approach
public static IEnumerable<T> Shuffle<T> (this IEnumerable<T> source)
{
Random random = new Random ();
return source.OrderBy(i => Random.Next()).AsEnumerable();
}
The orignal answer but slower than the edits
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> sequence)
{
Random random = new Random();
List<T> copy = sequence.ToList();
while (copy.Count > 0)
{
int index = random.Next(copy.Count);
yield return copy[index];
copy.RemoveAt(index);
}
}
If you like one of these you should up vote the linked answer.
If you are very concerned about randomness, you could upgrade to one of the RNG algorithms from the Crypto API and seed it with some non deterministic value, like somthing generated from recent mouse activity. I suspect that would be overkill and it would degrade performance.
class Randomizor<T>
{
public Randomizor()
{
}
public List<T> Shuffle(List<T> toShuffle)
{
}
}
class Randomizer<T>
{
public Randomizer(ICollection<T> collection)
{
//Do something with collection using T as the type of the elements
}
}
However you may want to go for a generic extension method
static class Randomizer
{
public static void Randomize<T>(this ICollection<T> collection)
{
//randomize the collection
}
}
and the usage:
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
list.Randomize();
Maybe like this:
public List<T> Shuffle<T>(List<T> toShuffle)
{
return toShuffle.OrderBy(x => Guid.NewGuid()).ToList();
}
Or as an extension method
public static class Extensions
{
public static List<T> Shuffle<T>(this List<T> toShuffle)
{
return toShuffle.OrderBy(x => Guid.NewGuid()).ToList();
}
}

Categories

Resources