How to get the relative position of a Dictionary element? - c#

I have the next C# code:
Dictionary<string, int> d = new Dictionary<string, int>();
d.Add("a", 3);
d.Add("b", 1);
d.Add("c", 0);
d.Add("d", -1);
d.Add("e", -9);
When searching the key "c" I want to get the position of this key, i.e. 2. If I look for the key "e", I want to get 4. If the element is not found the relative position could be -1.
Added:
Unless you have a better idea, I want to populate a matrix with certain values in a row number indicated by the relative position of a dictionary element found. The same applies for the column but using a different dictionary. An example:
n4 n2 n1 n3 n9 . . .
a 4/4
b 2 8
c
d 8/2
e 4/3
.
.
.
Where a,b,c,d,e,... are the keys of dictionay "d" and n4,n2,n3,n9 are the keys of a second dictionary.
How can I get this?

There's no such thing as a "position" within a Dictionary<,> - it's an unordered collection.
There are similar collections sorted by key - SortedList<,> and SortedDictionary<,>. Note that those are ordered by key rather than insertion time though. It's not clear which you want.

This should do the trick:
d.Keys.ToList().IndexOf("c");
Please Note that the O(1) time lookup offered by the Dictionary is lost when converting to the List, because Lists are inherently O(n). So if your Dictionary has a large number of elements, you're probably better off using another Dictionary or Matrix dimension to store the positions, since retrieving them in this manner will likely be slower. In fact, you should probably assume that the one-liner above is similar to:
GetDictKeyPos(d, "c");
public int GetDictKeyPos(Dictionary<string, int> d, string key)
{
for (int i = 0; i < d.Count; ++i)
{
if (d.ElementAt(i).Key == key)
return i;
}
return -1;
}
As a side note, if you are trying to get the position, you're probably making the assumption that the position is preserved. Microsoft says don't count on it, but in practice you'll discover that you probably can count on it. (I've never seen position not be preserved.) That being said, until Microsoft admits that, "Yeah, yeah, we've been holding out on you: position actually is preserved in a Dictionary. We just didn't want to admit it because we wanted to be able to change it if we found a better implementation, but now we know we're going to leave it, so here ya go...", you probably shouldn't assume that position is preserved.
Lastly, if you are planning to take your chances and assume it's preserved, and you also plan to use the above method to get the position, then consider storing the keys in a List instead, since the lookup time will be the same, and List order is guaranteed to be preserved.

Dictionaries have no implied order of key-value pairs. If you need the "position," you are using them the wrong way.
On your edit: If you are implementing a matrix, your best bet would be to use a multidimensional array. Eg:
int[,] matrix = new int[3, 2] { {1, 2}, {3, 4}, {5, 6} };
Is equivalent to a matrix like:
1 2
3 4
5 6
You can access its elements using matrix[i][j]; eg matrix[0][0] is 1, matrix[0][1] is 2, etc.

You will not be able to use any of the builtin collection data structures including KeyedCollection. However, you can easily make your own collection class by deriving from Collection and which contains a Dictionary internally for quick lookups on the key. The Collection class itself provides the ability for indexed retrieval.
public class KeyValueCollection<TKey, TValue> : Collection<KeyValuePair<TKey, TValue>>
{
private Dictionary<TKey, TValue> m_Dictionary = new Dictionary<TKey, TValue>();
public TValue GetValue(TKey key)
{
return m_Dictionary[key];
}
public void Add(TKey key, TValue value)
{
m_Dictionary.Add(key, value);
base.Add(new KeyValuePair<TKey, TValue>(key, value));
}
protected override void ClearItems()
{
m_Dictionary.Clear();
base.ClearItems();
}
protected override void InsertItem(int index, KeyValuePair<TKey, TValue> item)
{
m_Dictionary.Add(item.Key, item.Value);
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
m_Dictionary.Remove(this[index].Key);
base.RemoveItem(index);
}
protected override void SetItem(int index, KeyValuePair<TKey, TValue> item)
{
m_Dictionary[this[index].Key] = item.Value;
base.SetItem(index, item);
}
}

If you are really looking for that functionality, why don't you maintain an auxilary data structure which maintains the order in which you added the elements
(OR)
Probably you want to just maintain a List of Structures which store
[{"a",-1},{"b",1},{"c",0},{"d",-1},{"e",-9}]

Related

How to get the last value entered [duplicate]

My dictionary:
Dictionary<double, string> dic = new Dictionary<double, string>();
How can I return the last element in my dictionary?
What do you mean by Last? Do you mean Last value added?
The Dictionary<TKey,TValue> class is an unordered collection. Adding and removing items can change what is considered to be the first and last element. Hence there is no way to get the Last element added.
There is an ordered dictionary class available in the form of SortedDictionary<TKey,TValue>. But this will be ordered based on comparison of the keys and not the order in which values were added.
EDIT
Several people have mentioned using the following LINQ style approach
var last = dictionary.Values.Last();
Be very wary about using this method. It will return the last value in the Values collection. This may or may not be the last value you added to the Dictionary. It's probably as likely to not be as it is to be.
Dictionaries are unordered collections - as such, there is no concept of a first or last element. If you are looking for a class that behaves like a dictionary but maintains the insertion order of items, consider using OrderedDictionary.
If you are looking for a collection that sorts the items, consider using SortedDictionary<TKey,TValue>.
If you have an existing dictionary, and you are looking for the 'last' element given some sort order, you could use linq to sort the collection, something like:
myDictionary.Values.OrderBy( x => x.Key ).Last();
By wary of using Dictionary.Keys.Last() - while the key list is sorted using the default IComparer for the type of the key, the value you get may not be the value you expect.
I know this question is too old to get any upvotes, but I didn't like any of the answers so will post my own in the hopes of offering another option to future readers.
Assuming you want the highest key value in a dictionary, not the last inserted:
The following did not work for me on .NET 4.0:
myDictionary.Values.OrderBy( x => x.Key ).Last();
I suspect the problem is that the 'x' represents a value in the dictionary, and a value has no key (the dictionary stores the key, the dictionary values do not). I may also be making a mistake in my usage of the technique.
Either way, this solution would be slow for large dictionaries, probably O(n log n) for CS folks, because it is sorting the entire dictionary just to get one entry. That's like rearranging your entire DVD collection just to find one specific movie.
var lastDicVal = dic.Values.Last();
is well established as a bad idea. In practice, this solution may return the last value added to the dictionary (not the highest key value), but in software engineering terms that is meaningless and should not be relied upon. Even if it works every time for the rest of eternity, it represents a time bomb in your code that depends on library implementation detail.
My solution is as follows:
var lastValue = dic[dic.Keys.Max()];
The Keys.max() function is much faster than sorting O(n) instead of O(n log n).
If performance is important enough that even O(n) is too slow, the last inserted key can be tracked in a separate variable used to replace dic.Keys.Max(), which will make the entire lookup as fast as it can be, or O(1).
Note: Use of double or float as a key is not best practice and can yield surprising results which are beyond the scope of this post. Read about "epsilon" in the context of float/double values.
If you're using .NET 3.5, look at:
dic.Keys.Last()
If you want a predictable order, though, use:
IDictionary<int, string> dic = new SortedDictionary<int, string>();
Instead of using:
Dictionary<double, string>
...you could use:
List<KeyValuePair<double, string>>
This would allow you to use the indexer to access the element by order instead of by key.
Consider creating a custom collection that contains a reference in the Add method of the custom collection. This would set a private field containing the last added key/value(or both) depending on your requirements.
Then have a Last() method that returns this. Here's a proof of concept class to show what I mean (please don't knock the lack of interface implementation etc- it is sample code):
public class LastDictionary<TKey, TValue>
{
private Dictionary<TKey, TValue> dict;
public LastDictionary()
{
dict = new Dictionary<TKey, TValue>();
}
public void Add(TKey key, TValue value)
{
LastKey = key;
LastValue = value;
dict.Add(key, value);
}
public TKey LastKey
{
get; private set;
}
public TValue LastValue
{
get; private set;
}
}
From the docs:
For purposes of enumeration, each item
in the dictionary is treated as a
KeyValuePair structure representing a
value and its key. The order in which
the items are returned is undefined.
So, I don't think you can rely on Dictionary to return the last element.
Use another collection. Maybe SortedDictionary ...
If you just want the value, this should work (assuming you can use LINQ):
dic.Values.Last()
You could use:
dic.Last()
But a dictionary doesn't really have a last element (the pairs inside aren't ordered in any particular way). The last item will always be the same, but it's not obvious which element it might be.
With .Net 3.5:
string lastItem = dic.Values.Last()
string lastKey = dic.Keys.Last()
...but keep in mind that a dictionary is not ordered, so you can't count on the fact that the values will remain in the same order.
A dictionary isn't meant to be accessed in order, so first, last have no meaning. Do you want the value indexed by the highest key?
Dictionary<double, string> dic = new Dictionary<double, string>();
double highest = double.MinValue;
string result = null;
foreach(double d in dic.keys)
{
if(d > highest)
{
result = dic[d];
highest = d;
}
}
Instead of using Linq like most of the other answers suggest, you can just access the last element of any Collection object via the Count property (see ICollection.Count Property for more information).
See the code here for an example of how to use count to access the final element in any Collection (including a Dictionary):
Dictionary<double, string> dic = new Dictionary<double, string>();
var lastElementIndex = dic.Count - 1;
var lastElement = dic[lastElementIndex];
Keep in mind that this returns the last VALUE, not the key.

Looking for something like a HashSet, but with a range of values for the key?

I'm wondering if there is something like HashSet, but keyed by a range of values.
For example, we could add an item which is keyed to all integers between 100 and 4000. This item would be returned if we used any key between 100 and 4000, e.g. 287.
I would like the lookup speed to be quite close to HashSet, i.e. O(1). It would be possible to implement this using a binary search, but this would be too slow for the requirements. I would like to use standard .NET API calls as much as possible.
Update
This is interesting: https://github.com/mbuchetics/RangeTree
It has a time complexity of O(log(N)) where N is number of intervals, so it's not exactly O(1), but it could be used to build a working implementation.
I don't believe there's a structure for it already. You could implement something like a RangedDictionary:
class RangedDictionary {
private Dictionary<Range, int> _set = new Dictionary<Range, int>();
public void Add(Range r, int key) {
_set.Add(r, key);
}
public int Get(int key) {
//find a range that includes that key and return _set[range]
}
}
struct Range {
public int Begin;
public int End;
//override GetHashCode() and Equals() methods so that you can index a Dictionary by Range
}
EDIT: changed to HashSet to Dictionary
Here is a solution you can try out. However it assumes some points :
No range overlaps
When you request for a number, it is effectively inside a range (no error check)
From what you said, this one is O(N), but you can make it O(log(N)) with little effort I think.
The idea is that a class will handle the range thing, it will basically convert any value given to it to its range's lower boundary. This way your Hashtable (here a Dictionary) contains the low boundaries as keys.
public class Range
{
//We store all the ranges we have
private static List<int> ranges = new List<int>();
public int value { get; set; }
public static void CreateRange(int RangeStart, int RangeStop)
{
ranges.Add(RangeStart);
ranges.Sort();
}
public Range(int value)
{
int previous = ranges[0];
//Here we will find the range and give it the low boundary
//This is a very simple foreach loop but you can make it better
foreach (int item in ranges)
{
if (item > value)
{
break;
}
previous = item;
}
this.value = previous;
}
public override int GetHashCode()
{
return value;
}
}
Here is to test it.
class Program
{
static void Main(string[] args)
{
Dictionary<int, int> myRangedDic = new Dictionary<int,int>();
Range.CreateRange(10, 20);
Range.CreateRange(50, 100);
myRangedDic.Add(new Range(15).value, 1000);
myRangedDic.Add(new Range(75).value, 5000);
Console.WriteLine("searching for 16 : {0}", myRangedDic[new Range(16).value].ToString());
Console.WriteLine("searching for 64 : {0}", myRangedDic[new Range(64).value].ToString());
Console.ReadLine();
}
}
I don't believe you really can go below O(Log(N)) because there is no way for you to know immediately in which range a number is, you must always compare it with a lower (or upper) bound.
If you had predetermined ranges, that would have been easier to do. i.e. if your ranges are every hundreds, it is really easy to find the correct range of any number by calculating it modulo 100, but here we can assume nothing, so we must check.
To go down to Log(N) with this solution, just replace the foreach with a loop that will look at the middle of the array, then split it in two every iteration...

C# ordered dictionary object that supports finding closest key?

Is there any ordered dictionary collection available in C# that provides a ready means of finding the first key greater than a value if the sought value isn't present?
I.e., if (!Dictionary.ContainsKey(some_key)) then return the next key > some_key based on the dictionary's ordering predicate?
If there's a clever way of doing this with delegates an example of that would be equally appreciated!
As Vadim suggested, your best bet would be the SortedDictionary implementation which stores the keys sorted. From there you could do the following:
var next = dictionary.ContainsKey(key)
? dictionary[key]
: dictionary.FirstOrDefault(kvp => kvp.Key > key).Value;
The dictionary.FirstOrDefault will return the first key value pair where the key is greater than the desired key. If there are none, then a blank key-value pair is returned {,} and the value returned should be the default value of the type stored. Since I was playing with a SortedDictionary, it returned null.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var dictionary = new SortedDictionary<int, string> {{1, "First"}, {2, "Second"}, {10, "10th"}};
Console.WriteLine(GetNext(1, dictionary));
Console.WriteLine(GetNext(3, dictionary));
Console.WriteLine(GetNext(11, dictionary));
Console.ReadLine();
}
private static string GetNext(int key, SortedDictionary<int, string> dictionary)
{
return dictionary.ContainsKey(key)
? dictionary[key]
: dictionary.FirstOrDefault(kvp => kvp.Key > key).Value;
}
}
}
Here is a great binary-search implementation for any sorted IList: If the exact key doesn't exist, it returns the ~index of the next greatest key.
With that class in scope one can just do something like the following:
SortedList myList;
int nextBiggestKey; // Index of key >= soughtValue
if((nextBiggestKey = myList.Keys.BinarySearch(soughtValue)) < 0)
{
if(~nextBiggestKey > myList.Count) continue; // soughtValue is larger than largest key in myList
nextBiggestKey = ~nextBiggestKey
}

Get A random keyValue from Hashtable

I Have a Hashtable that I dont know What is the content of .
now I want to get one Key and value from it;
I use hashtable because of its speed because content of hashtable is over 4,500,000 KeyValuePair so I cant use GetEnumerator its reduce program speed
You use a List<TKey>:
Dictionary<string, string> dict = ... your hashtable which could be huge
List<string> keys = new List<string>(dict.Keys);
int size = dict.Count;
Random rand = new Random();
string randomKey = keys[rand.Next(size)];
We are just creating a List<TKey> whose elements are pointing to the same location in memory as the keys of your hashtable and then we pick a random element from this list.
And if you want to get a random element value from the hashtable, this should be pretty straightforward given a random key.
string randomeElement = dict[randomKey];
I cant use GetEnumerator its reduce program speed"
Well that's a problem. You've accepted an answer which does iterate over all the entries, and also copies the keys into a new list, so it's not clear whether you've abandoned that requirement.
An approach which will certainly be more efficient in memory and potentially in speed as well is to iterate over the whole dictionary, but retaining a random element at any one time, with an optimization for collections where we can obtain the count cheaply. Here's an extension method which will do that for any generic sequence in .NET:
public static T RandomElement<T>(this IEnumerable<T> source,
Random rng)
{
// Optimize for the "known count" case.
ICollection<T> collection = source as ICollection<T>;
if (collection != null)
{
// ElementAt will optimize further for the IList<T> case
return source.ElementAt(rng.Next(collection.Count));
}
T current = default(T);
int count = 0;
foreach (T element in source)
{
count++;
if (rng.Next(count) == 0)
{
current = element;
}
}
if (count == 0)
{
throw new InvalidOperationException("Sequence was empty");
}
return current;
}
So for a Dictionary<TKey, TValue> you'd end up with a KeyValuePair<TKey, TValue> that way - or you could project to Keys first:
var key = dictionary.Keys.RandomElement(rng);
(See my article on Random for gotchas around that side of things.)
I don't believe you'll be able to do any better than O(n) if you want a genuinely pseudo-random key, rather than just an arbitrary key (which you could get by taking the first one in the sequence, as stated elsewhere).
Note that copying the keys to a list as in Darin's answer allows you to get multiple random elements more efficiently, of course. It all depends on your requirements.
How random does the random key have to be?
Hash tables don't define an order for their items to be stored in, so you could just grab the first item. It's not really random, but it's not insertion order or sorted order either. Would that be random enough?
Dictionary<string, string> dict = GetYourHugeHashTable();
KeyValuePair<string, string> randomItem = dict.First();
DoAComputation(randomItem.Key, randomItem.Value);
dict.Remove(randomItem.Key);
with Linq you can do:
Dictionary<string, string> dicto = new Dictionary<string, string>();
Random rand = new Random();
int size = dicto.Count;
int randNum = rand.Next(0, size);
KeyValuePair<string, string> randomPair = dicto.ElementAt( randNum );
string randomVal = randomPair.Value;
For instance,
string tmp = dicto.ElementAt( 30 ).Value;
Would copy the value of the thirtieth item in the Dicto to the string tmp.
Internally, I think it walks through the keypairs one at a time, till it gets to the thirtieth, instead of copying them all, so you don't need to load all the elements into memory.
I'm not sure what you meant by not knowing what the content is.
You don't know the types in the KeyValuePair of the dicto?
Or just don't know what values will be in the dicto?
Hashtable.Keys will give you a pointer to the internal list of keys. That is speedy. Also removing an item from a Hashtable is an O(1) operation, so this will also be speedy, even with large amounts of items.
You could do a loop like this (I see no reason to use random in your question);
var k = Hashtable.Keys(); // Will reflect actual contents, even if changes occur
while (k.Count > 0 )
{
var i = Keys.First();
{
Process(i);
Hashtable.Remove(i)
}
}
Well, if you know which version of the .NET BCL you'll be targeting (i.e., if it's fixed), you could always plumb the internals of Dictionary<TKey, TValue> to figure out how it stores its keys privately and use that to pluck a random one.
For example, using the version of Mono I currently have installed on my work laptop, I see that the Dictionary<TKey, TValue> type has a private field called keySlots (I assume this will be different for you if you're on Windows). Using this knowledge you could implement a function looking something like this:
static readonly Dictionary<Type, FieldInfo> KeySlotsFields = new Dictionary<Type, FieldInfo>();
public static KeyValuePair<TKey, TValue> GetRandomKeyValuePair<TKey, TValue>(this Random random, Dictionary<TKey, TValue> dictionary, Random random = null)
{
// Here's where you'd get the FieldInfo that you've identified
// for your target version of the BCL.
FieldInfo keySlotsField = GetKeySlotsField<TKey, TValue>();
var keySlots = (TKey[])keySlotsField.GetValue(dictionary);
var key = (TKey)keySlots[random.Next(keySlots.Length)];
// The keySlots field references an array with some empty slots,
// so we need to loop until we come across an existing key.
while (key == null)
{
key = (TKey)keySlots[random.Next(keySlots.Length)];
}
return new KeyValuePair<TKey, TValue>(key, dictionary[key]);
}
// This happens to work for me on Mono; you'd almost certainly need to
// rewrite it for different platforms.
public FieldInfo GetKeySlotsField<TKey, TValue>()
{
Type keyType = typeof(TKey);
FieldInfo keySlotsField;
if (!KeySlotsFields.TryGetValue(keyType, out keySlotsField))
{
KeySlotsFields[keyType] = keySlotsField = typeof(Dictionary<TKey, TValue>).GetField("keySlots", BindingFlags.Instance | BindingFlags.NonPublic);
}
return keySlotsField;
}
This could be an appropriate solution in your case, or it could be a horrible idea. Only you have enough context to make that call.
As for the example method above: I personally like adding extension methods to the Random class for any functionality involving randomness. That's just my choice; obviously you could go a different route.

How does a STL multimap differ from a .NET Dictionary<key, List<values>>?

I have a problem where I need a .NET dictionary that supports multiple items per key. In the past I've used the STL multimap in my C++ programs. How does the design of a multimap differ from a dictionary of lists i.e. performance, size, etc. (excluding generics vs. templates)?
multimap.count: O(log n + m) where n is number of keys and m is number of items associated with a given key.
For a Dictionary<TKey, List<TValue>> the equivalent functionality would be:
int count = dictionary[key].Count;
And safer is to say
int count;
List<TValue> list;
if(dictionary.TryGetValue(key, out list)) {
int count = list.Count;
}
This is an O(1) operation because lookup is O(1)1 and List<T>.Count is O(1).
multimap.find: O(log n) where n is number of keys
For a Dictionary<TKey, List<TValue>> the equivalent functionality would be:
List<TValue> elements = dictionary[key];
And safer is to say
List<TValue> list;
if(dictionary.TryGetValue(key, out list)) {
// safe to iterate list
}
This is O(1). See the previous remark on lookup by key in a Dictionary<TKey, TValue>.
multimap.insert: O(log n) where n is the number of keys.
For a Dictionary<TKey, List<TValue>> the equivalent functionality would be:
// value is TValue to insert
List<TValue> list;
if(!dictionary.TryGetValue(key, out list)) {
list = new List<TValue>();
dictionary.Add(key, list);
}
list.Add(value);
This is usually O(1) but can be O(n) when the capacity of the dictionary must be increased to accomodate the new element.
multimap.remove: There are three overloads of this method; I will only consider the one that accepts a key and removes all occurrences of that key from the multimap. This is an O(log n + m) operation where there n keys and m objects associate with a given key.
For a Dictionary<TKey, List<TValue>> the equivalent functionality would be:
dictionary.Remove(key);
From the documentation: "This method approaches an O(1) operation." Same comment applies.
1: From the documentation: "Retrieving a value by using its key is very fast, close to O(1)." Why the documentation is vague on this point is confusing to me. Either an operation is O(1) or it isn't. There is no such thing as "close" to O(1).
multimap:
insert/remove operations take logarithmic time Big-O(log n),
lookup take constant time Big-O(1).
Each element is accessed using a key value, unlike the map, a multimap key value needs not be unique, associated values do not need to be unique. The map orders the elements by their keys using a stored function key_compare, which simply does a less-than comparison.
Here's
an article on IDictionary performance which doesn't mention any Big-O performance metrics but does give some practical runs using the dictionary.

Categories

Resources