SortedDictionary duplicate keys? - c#

Okai, i have the following method:
public void Insert(SortedDictionary<byte[], uint> recs)
{
SortedDictionary<byte[], uint> records = new SortedDictionary(recs, myComparer);
}
What I am hoping to achieve is to sort the records in "recs" with a new rule specified by "myComparer" which implements IComparer. It pretty much does so, but I get hit by an exception with the following message:
An entry with the same key already
exists.
I am wondering how this is possible since "recs" is already a dictionary with about 130k keys.
public int Compare(byte[] a, byte[] b)
{
return Inhouse.ByteConverter.ToString(a).CompareTo(
Inhouse.ByteConverter.ToString(b));
}
(it's just a snipette..)

If "recs" has a different comparer than the one you inject into records you may get duplicates; that is if "recs" compares by object reference and myComparer compares the actual bytes, you will have collisions.

Check the comparer code:
Every key in a SortedDictionary(Of
TKey, TValue) must be unique according
to the specified comparer; therefore, every key in the source dictionary must also be
unique according to the specified comparer.
with your new comparer, 2 different keys with normal byte[] comparaison may become equal.
It's what msdn says...

You must be using the same Dictionary object in the calling method. So I imagine your code is something like this:
SortedDictionary<byte[], uint> dic = new SortedDictionary<byte[], uint>();
foreach (var thing in things)
{
dic.Clear();
Populate(dic);
Insert(dic);
}
Where it should be like this:
SortedDictionary<byte[], uint> dic = new SortedDictionary<byte[], uint>();
foreach (var thing in things)
{
dic = new SortedDictionary<byte[], uint>();
Populate(dic);
Insert(dic);
}
Can you post the code that is calling your Insert method?

Related

How to get original case key by case insensitive key in Dictionary<string, int>

There is Dictionary:
var dictionary1 = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
{{"abc1", 1}, {"abC2", 2}, {"abc3", 3}};
I can get a value:
var value = dictionary1["Abc2"];
If search key "Abc2" I need to get the original key "abC2" and value 2.
How to get original case key by case insensitive key?
You can't do that, unfortunately. It would be entirely reasonable for Dictionary<TKey, TValue> to expose a bool TryGetEntry(TKey key, KeyValuePair<TKey, TValue> entry) method, but it doesn't do so.
As stop-cran suggested in comments, the simplest approach is probably to make each value in your dictionary a pair with the same key as the key in the dictionary. So:
var dictionary = new Dictionary<string, KeyValuePair<string, int>>(StringComparer.OrdinalIgnoreCase)
{
// You'd normally write a helper method to avoid having to specify
// the key twice, of course.
{"abc1", new KeyValuePair<string, int>("abc1", 1)},
{"abC2", new KeyValuePair<string, int>("abC2", 2)},
{"abc3", new KeyValuePair<string, int>("abc3", 3)}
};
if (dictionary.TryGetValue("Abc2", out var entry))
{
Console.WriteLine(entry.Key); // abC2
Console.WriteLine(entry.Value); // 2
}
else
{
Console.WriteLine("Key not found"); // We don't get here in this example
}
If this is a field in a class, you could write helper methods to make it simpler. You could even write your own wrapper class around Dictionary to implement IDictionary<TKey, TValue> but add an extra TryGetEntry method, so that the caller never needs to know what the "inner" dictionary looks like.
You can use following code that utilizes LINQ to get dictionary key value pair even when case is not matching for key.
NOTE: This code can be used for dictionary of any size, but it's most appropriate for smaller size dictionaries since the LINQ is basically checking each key value pair one by one as opposed to directly going to the desired key value pair.
Dictionary<string,int> dictionary1 = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
{
{"abc1",1},
{"abC2",2},
{"abc3",3}
} ;
var value1 = dictionary1["ABC2"];//this gives 2, even though case of key does not macth
//use LINQ to achieve your requirement
var keyValuePair1 = dictionary1.SingleOrDefault (d => d.Key.Equals("Abc2", StringComparison.OrdinalIgnoreCase) );
var key1 = keyValuePair1.Key ;//gives us abC2
var value2 =keyValuePair1.Value;//gives us 2

C# - Tuple or other multikey variant for Dictionary, but with permutability

I am scratching my head over the following problem.
I want to create a dictionary, which uses multiple keys. I came along the solutions suggesting tuples as the method of choice. I think this i a good way to go. However my problem has the following speciality. I would like to make the keys "permutable" (Sorry, if I am using the wrong slang here). What I mean with this, is the following. I want the result of dict[<key1,key2> to be the same as with dict[<key2,<key1>], because the data that I want to store is invariant to the order of keys.
As an example see the following code, which of course does at the moment not yield the result I am hoping for. I want the result with permuted key to be the same as for the key-tuple.
Tuple<string, string> key = new Tuple<string, string>("Name1", "Name2");
Dictionary<Tuple<string,string>, double> dict = new Dictionary<Tuple<string, string>, double>();
dict.Add(key, 5.0);
Console.WriteLine(dict[key]);
Tuple<string, string> permutedKey = new Tuple<string, string>("Name2", "Name1");
Console.WriteLine(dict[permutedKey]);
The reason for all this, I have to store data, which has to be indexed with two keys, but is essentially always symetrical. So there is no need, to store it two times.
You can define your own custom equality comparer and use it in the dictionary:
class TupleComparer<T> : IEqualityComparer<Tuple<T, T>>
{
public bool Equals(Tuple<T, T> x, Tuple<T, T> y)
{
return object.Equals(x.Item1, y.Item1) && object.Equals(x.Item2, y.Item2) ||
object.Equals(x.Item1, y.Item2) && object.Equals(x.Item2, y.Item1);
}
public int GetHashCode(Tuple<T, T> obj)
{
return obj.Item1.GetHashCode() + obj.Item2.GetHashCode();
}
}
Then, you can create the dictionary passing it an instance of the comparer:
Tuple<string, string> key = new Tuple<string, string>("Name1", "Name2");
Dictionary<Tuple<string,string>, double> dict =
new Dictionary<Tuple<string, string>, double>(new TupleComparer<string>());
dict.Add(key, 5.0);
Console.WriteLine(dict[key]);
var permutedKey = new Tuple<string, string>("Name2", "Name1");
Console.WriteLine(dict[permutedKey]);
You will need to define your own class with two elements and implement IComparable where CompareTo will be written as per you requirement. Then use that class as Key for your Dictionary. Also, please override method GetHashCode too.
Is comparing List<string> a viable option for your use case? If so, I'd recommend this stack overflow anser:
Compare two List<T> objects for equality, ignoring order
If you can't use List<string>, then I'd agree with rbaghbanli's answer.

Sort the value in SortedList by ascending order

I am using SortedList in my application.By default the list is ordered by key in ascending order.I need to order the SortedList by values in ascending order and not by key.
SortedList sortinlist = new SortedList();
public bool Add(string val1, string val2)
{
Reading reading = new Reading(val1, val2);
sortinlist .Add(val1, val2);
return true;
}
I goggled with this same topic and refereed some thread,i am not clear in performing this.Can any one help me in doing this.
Thanks
You could use the generic version of the SortedList, for sample:
include the Linq namespace:
using System.Linq;
and try this:
SortedList<string, string> sortinlist = new SortedList<string, string>();
var result = sortinlist.OrderBy(x => x.Value).ToList();
You will not get a new SortedList because the default behaviour is ordered by Key.
As #Tim comment bellow, you could try with the non-generic version with the Cast<> method to convert the ouput to a IEnumerable<DictionaryEntry> and order from there.
var result = sortinlist.Cast<DictionaryEntry>().OrderBy(x => x.Value);
If the values are guaranteed to be unique, you can use two SortedLists or SortedDictionaries (by the way, SortedDictionary is much more efficient if you are inserting data out of order, so I'll use that for the second collection):
SortedList sortinlist = new SortedList();
SortedDictionary valueOrder = new SortedDictionary<string, string>();
public bool Add(string val1, string val2)
{
Reading reading = new Reading(val1, val2);
sortinlist.Add(val1, val2);
valueOrder.Add(val2, val1);
return true;
}
If the values are not guaranteed to be unique, then you can either calculate a new collection whenever you need the data in value order (here, I assume that sortinlist is a SortedList<string, string> or some other type that implements IDictionary<string, string>):
var valueOrder = sortinlist.OrderBy(kvp => kvp.Value).ToList();
... or maintain a separate collection:
SortedList<string, string> sortinlist = new SortedList<string, string>();
List<KeyValuePair<string, string>> valueOrder = new List<KeyValuePair<string, string>>();
public bool Add(string val1, string val2)
{
Reading reading = new Reading(val1, val2);
sortinlist.Add(val1, val2);
int targetIndex = /* to do: calculate proper index */
valueOrder.Insert(targetIndex, new KeyValuePair<string, string>(val2, val1));
return true;
}
If you are using the SortedList only because you were hoping to be able to sort it by values, use Dictionary<string, string> instead.
Maybe you should reconsider changing the data and data structure you are using. As written in the documentation page for the SortedList, it "Represents a collection of key/value pairs that are sorted by the keys and are accessible by key and by index."
This means that you have to use some other data structure that is more appropriate for your case (a List <KeyValuePair<TKey,TVal>> for example) and sort it by value.
This is what I did in order to sort the list per the required order.
Sort the table from the query
Add lpad with leading zeros ( e.g. key_value.PadLeft(4, '0');)
Add the Key Value pair to the sorted list
Now the list is already sorted as I intended.

I need to create a dictionary where each key can map to several values

Im trying to figure out how I can create something similar to a dictionary, but where each key can map to several values.
Basically what I need is to be able to assign multiple values to the same key without knowing in advance how many values each key will correspond to. I also need to be able to add values to an existing key on multiple occasions. It would also be nice if I could detect when a key + value combination already exists.
An example of how the program should work:
list.Add(1,5);
list.Add(3,6);
list.Add(1,7);
list.Add(5,4);
list.Add(1,2);
list.Add(1,5);
This should ideally produce a table like this:
1: 5, 7, 2
3: 6
5: 4
Is there any existing construction in C# that I can use for this or do I have to implement my own class? Implementing the class would probably not be a big problem, but Im a bit short on time so it would be nice if I could use something that already exists.
Quick Solution
As you have already mentioned, a Dictionary would be the best type to use. You can specify both the key type and value type to meet your needs, in your case you want an int key and a List<int> value.
This is easy enough to create:
Dictionary<int, List<int>> dictionary = new Dictionary<int, List<int>>();
The challenge then comes with how you add records, you cannot simply do Add(key, value) because that will cause conflict which duplicate keys. So you have to first retrieve the list (if it exists) and add to that:
List<int> list = null;
if (dictionary.ContainsKey(key))
{
list = dictionary[key];
}
else
{
list = new List<int>();
dictionary.Add(key, list);
}
list.Add(newValue);
Preferred Solution
This is obviously a few too many lines to use each time you want to add an item, so you would want to throw that into a helper function, or my preference would be to create your own class that extends the functionality of Dictionary. Something like this:
class ListDictionary<T1, T2> : Dictionary<T1, List<T2>>
{
public void Add(T1 key, T2 value)
{
if (this.ContainsKey(key))
{
this[key].Add(value);
}
else
{
List<T2> list = new List<T2>() { value };
this.Add(key, list);
}
}
public List<T2> GetValues(T1 key)
{
if(this.ContainsKey(key))
return this[key];
return null;
}
}
Which you can then use as easy as you originally wanted:
ListDictionary<int, int> myDictionary = new ListDictionary<int, int>();
myDictionary.Add(1,5);
myDictionary.Add(3,6);
//...and so on
Then to get the list of values for your desired key:
List<int> keyValues = myDictionary.GetValues(key);
//check if NULL before using, NULL means the key does not exist
//alternatively you can check if the key exists with if (myDictionary.ContainsKey(key))
You can create a dictionary of Lists quite easily e.g.
Dictionary<int, List<int>> dictionary = new Dictionary<int, List<int>>()
An Alternative if you have created a list of items and want to separate them into groups with different keys, which serves much the same purpose is the Lookup class.
Dictionary<int, List<int>> dictionary = new Dictionary<int, List<int>>();
public void AddIfNotExistInDic(int key, int Value) {
List<int> list = null;
if (dictionary.ContainsKey(key)) {
list = dictionary[key];
}
else {
list = new List<int>();
dictionary.Add(key, list);
}
if (!list.Contains(Value)) {
list.Add(Value);
}
}
You can use Dictionary<TKey, TValue>, the TKey would be int and TValue would be List<int>, You can add as many element in List as it grow autmatically.
Dictionary <int, List<int>> dic = new Dictionary<int, List<int>>();
The way you can access the value would change, you can for instance add element in dictionary like
void AddToYourCustomDictionary(int key, int someValue)
{
if(!dic.ContainsKey(key))
{
dic.Add(key, new List<int>());
dic[key].Add(someValue);
}
else
dic[key].Add(someValue); //Adding element in existing key Value pair
}
To access element in Dictionary Key -> value i.e list,
Console.WriteLine(dic[key][indexOfList]);

Accessing a Dictionary.Keys Key through a numeric index

I'm using a Dictionary<string, int> where the int is a count of the key.
Now, I need to access the last-inserted Key inside the Dictionary, but I do not know the name of it. The obvious attempt:
int LastCount = mydict[mydict.keys[mydict.keys.Count]];
does not work, because Dictionary.Keys does not implement a []-indexer.
I just wonder if there is any similar class? I thought about using a Stack, but that only stores a string. I could now create my own struct and then use a Stack<MyStruct>, but I wonder if there is another alternative, essentially a Dictionary that implements an []-indexer on the Keys?
As #Falanwe points out in a comment, doing something like this is incorrect:
int LastCount = mydict.Keys.ElementAt(mydict.Count -1);
You should not depend on the order of keys in a Dictionary. If you need ordering, you should use an OrderedDictionary, as suggested in this answer. The other answers on this page are interesting as well.
You can use an OrderedDictionary.
Represents a collection of key/value
pairs that are accessible by the key
or index.
A Dictionary is a Hash Table, so you have no idea the order of insertion!
If you want to know the last inserted key I would suggest extending the Dictionary to include a LastKeyInserted value.
E.g.:
public MyDictionary<K, T> : IDictionary<K, T>
{
private IDictionary<K, T> _InnerDictionary;
public K LastInsertedKey { get; set; }
public MyDictionary()
{
_InnerDictionary = new Dictionary<K, T>();
}
#region Implementation of IDictionary
public void Add(KeyValuePair<K, T> item)
{
_InnerDictionary.Add(item);
LastInsertedKey = item.Key;
}
public void Add(K key, T value)
{
_InnerDictionary.Add(key, value);
LastInsertedKey = key;
}
.... rest of IDictionary methods
#endregion
}
You will run into problems however when you use .Remove() so to overcome this you will have to keep an ordered list of the keys inserted.
Why don't you just extend the dictionary class to add in a last key inserted property. Something like the following maybe?
public class ExtendedDictionary : Dictionary<string, int>
{
private int lastKeyInserted = -1;
public int LastKeyInserted
{
get { return lastKeyInserted; }
set { lastKeyInserted = value; }
}
public void AddNew(string s, int i)
{
lastKeyInserted = i;
base.Add(s, i);
}
}
You could always do this:
string[] temp = new string[mydict.count];
mydict.Keys.CopyTo(temp, 0)
int LastCount = mydict[temp[mydict.count - 1]]
But I wouldn't recommend it. There's no guarantee that the last inserted key will be at the end of the array. The ordering for Keys on MSDN is unspecified, and subject to change. In my very brief test, it does seem to be in order of insertion, but you'd be better off building in proper bookkeeping like a stack--as you suggest (though I don't see the need of a struct based on your other statements)--or single variable cache if you just need to know the latest key.
I think you can do something like this, the syntax might be wrong, havent used C# in a while
To get the last item
Dictionary<string, int>.KeyCollection keys = mydict.keys;
string lastKey = keys.Last();
or use Max instead of Last to get the max value, I dont know which one fits your code better.
I agree with the second part of Patrick's answer. Even if in some tests it seems to keep insertion order, the documentation (and normal behavior for dictionaries and hashes) explicitly states the ordering is unspecified.
You're just asking for trouble depending on the ordering of the keys. Add your own bookkeeping (as Patrick said, just a single variable for the last added key) to be sure. Also, don't be tempted by all the methods such as Last and Max on the dictionary as those are probably in relation to the key comparator (I'm not sure about that).
In case you decide to use dangerous code that is subject to breakage, this extension function will fetch a key from a Dictionary<K,V> according to its internal indexing (which for Mono and .NET currently appears to be in the same order as you get by enumerating the Keys property).
It is much preferable to use Linq: dict.Keys.ElementAt(i), but that function will iterate O(N); the following is O(1) but with a reflection performance penalty.
using System;
using System.Collections.Generic;
using System.Reflection;
public static class Extensions
{
public static TKey KeyByIndex<TKey,TValue>(this Dictionary<TKey, TValue> dict, int idx)
{
Type type = typeof(Dictionary<TKey, TValue>);
FieldInfo info = type.GetField("entries", BindingFlags.NonPublic | BindingFlags.Instance);
if (info != null)
{
// .NET
Object element = ((Array)info.GetValue(dict)).GetValue(idx);
return (TKey)element.GetType().GetField("key", BindingFlags.Public | BindingFlags.Instance).GetValue(element);
}
// Mono:
info = type.GetField("keySlots", BindingFlags.NonPublic | BindingFlags.Instance);
return (TKey)((Array)info.GetValue(dict)).GetValue(idx);
}
};
One alternative would be a KeyedCollection if the key is embedded in the value.
Just create a basic implementation in a sealed class to use.
So to replace Dictionary<string, int> (which isn't a very good example as there isn't a clear key for a int).
private sealed class IntDictionary : KeyedCollection<string, int>
{
protected override string GetKeyForItem(int item)
{
// The example works better when the value contains the key. It falls down a bit for a dictionary of ints.
return item.ToString();
}
}
KeyedCollection<string, int> intCollection = new ClassThatContainsSealedImplementation.IntDictionary();
intCollection.Add(7);
int valueByIndex = intCollection[0];
The way you worded the question leads me to believe that the int in the Dictionary contains the item's "position" on the Dictionary. Judging from the assertion that the keys aren't stored in the order that they're added, if this is correct, that would mean that keys.Count (or .Count - 1, if you're using zero-based) should still always be the number of the last-entered key?
If that's correct, is there any reason you can't instead use Dictionary<int, string> so that you can use mydict[ mydict.Keys.Count ]?
I don't know if this would work because I'm pretty sure that the keys aren't stored in the order they are added, but you could cast the KeysCollection to a List and then get the last key in the list... but it would be worth having a look.
The only other thing I can think of is to store the keys in a lookup list and add the keys to the list before you add them to the dictionary... it's not pretty tho.
To expand on Daniels post and his comments regarding the key, since the key is embedded within the value anyway, you could resort to using a KeyValuePair<TKey, TValue> as the value. The main reasoning for this is that, in general, the Key isn't necessarily directly derivable from the value.
Then it'd look like this:
public sealed class CustomDictionary<TKey, TValue>
: KeyedCollection<TKey, KeyValuePair<TKey, TValue>>
{
protected override TKey GetKeyForItem(KeyValuePair<TKey, TValue> item)
{
return item.Key;
}
}
To use this as in the previous example, you'd do:
CustomDictionary<string, int> custDict = new CustomDictionary<string, int>();
custDict.Add(new KeyValuePair<string, int>("key", 7));
int valueByIndex = custDict[0].Value;
int valueByKey = custDict["key"].Value;
string keyByIndex = custDict[0].Key;
A dictionary may not be very intuitive for using index for reference but, you can have similar operations with an array of KeyValuePair:
ex.
KeyValuePair<string, string>[] filters;
You can also use SortedList and its Generic counterpart. These two classes and in Andrew Peters answer mentioned OrderedDictionary are dictionary classes in which items can be accessed by index (position) as well as by key. How to use these classes you can find: SortedList Class , SortedList Generic Class .
Visual Studio's UserVoice gives a link to generic OrderedDictionary implementation by dotmore.
But if you only need to get key/value pairs by index and don't need to get values by keys, you may use one simple trick. Declare some generic class (I called it ListArray) as follows:
class ListArray<T> : List<T[]> { }
You may also declare it with constructors:
class ListArray<T> : List<T[]>
{
public ListArray() : base() { }
public ListArray(int capacity) : base(capacity) { }
}
For example, you read some key/value pairs from a file and just want to store them in the order they were read so to get them later by index:
ListArray<string> settingsRead = new ListArray<string>();
using (var sr = new StreamReader(myFile))
{
string line;
while ((line = sr.ReadLine()) != null)
{
string[] keyValueStrings = line.Split(separator);
for (int i = 0; i < keyValueStrings.Length; i++)
keyValueStrings[i] = keyValueStrings[i].Trim();
settingsRead.Add(keyValueStrings);
}
}
// Later you get your key/value strings simply by index
string[] myKeyValueStrings = settingsRead[index];
As you may have noticed, you can have not necessarily just pairs of key/value in your ListArray. The item arrays may be of any length, like in jagged array.

Categories

Resources