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
}
Related
I have Dictionary that the key is an array of int, and the value is a string. How can I get the value by check if int is contained in the key array?
public static Dictionary<int[], string> MyDic = new Dictionary<int[], string>
{
{new int[]{2,25},"firstValue"},
{new int[]{3,91,315,322},"secondValue"}
};
I have :
int number=91;
string value=?;
I need the value will get "secondValue"
I think this is a bad design choice. If the numbers don't repeat between keys (as you said in your comment for the question) then just flatten the keys into a simple Dictionary<int,string>. Just have the different integers all be keys for the same strings.
For example:
Dictionary<int,string>
{
[2] = "firstValue",
[25] = "firstValue",
};
In order to not repeat the same values but as different objects you can place a reference there:
string firstValue = "firstValue";
Dictionary<int,string>
{
[2] = firstValue,
[25] = firstValue,
};
In this case changing the value's content (not for a string as it is immutable but if it was some other object) for one key will change for all.
Use contains and a foreach loop (more readable than some other solutions):
string value;
int number = 91;
foreach(KeyValuePair<int[], string> entry in MyDic)
{
if (entry.Key.Contains(number))
{
value = entry.Value;
}
}
However, maybe a dictionary isn't the right choice for this.
Check out Gilads answer for another structure that you could use
string value = MyDic.FirstOrDefault(x => x.Key.Contains(number)).Value;
? is not needed, can not apply ? operand to KeyValuePair
something like
value = MyDic.FirstOrDefault(x => x.Key.Contains(number)).Value;
will return the first occurrence or null
In the below scenario how can I handle or implement collision in C# using the Hashtable class? If the 'Key' value is same I am getting an "Argument Exception".
static void Main(string[] args)
{
Console.Write("Enter a string:");
string input = Console.ReadLine();
checkString(input);
Console.ReadLine();
}
static void checkString(string input)
{
Hashtable hashTbl = new Hashtable();
foreach(char c in input)
{
hashTbl.Add(c.GetHashCode(), c);
}
printHash(hashTbl);
}
static void printHash(Hashtable hash)
{
foreach(int key in hash.Keys)
{
Console.WriteLine("Key: {0} Value: {1}",key,hash[key]);
}
}
My Expectation:
What do I need to do in the 'Value' argument to get around the 'Collision' issue. I am trying to check if the string consists of unique characters.
It seems you are misunderstanding how the Hashtable class works (and it has been deprecated since 2005 - use Dictionary<K,V> instead, but its behavior here is identical).
It seems you're expecting it to be your job to get an object's hashcode and add it to the hashtable. It isn't. All you need to do is add the object you want to use as key (each character), and the internal implementation will extract the hashcode.
However, what you're actually doing won't work even if you added the key object yourself. You're taking an input string (say, "test"), and for each character, you're adding it to the hashtable as a key. But since keys are, by definition, unique, you'll be adding the character 't' twice (it shows up twice in the input), so you'll get an exception.
I am trying to check if the string consists of unique characters.
Then you need keys only without values, that's what HashSet<T> is for.
var chars = new HashSet<char>();
foreach (char c in input)
{
if (chars.Contains(c))
{
// c is not unique
}
else
{
chars.Add(c);
}
}
But I'd prefer usin LINQ in this case:
var hasUniqueChars = input.Length == input.Distinct().Count();
As previously stated you should probably switch to the Dictionary<TKey, TValue> class for this.
If you want to get around the collission issue, then you have to check the key for existence.
Dictionary<string, object> dictValues = new Dictionary<string, object>();
Then you can use check for collission:
if (dictValues.ContainsKey(YourKey))
{
/* ... your collission handling here ... */
}
else
{
// No collission
}
Another possibility would be, if you are not interested in preserving previous values for the same key:
dictValues[YourKey] = YourValue;
This will add the key entry if it is not there already. If it is, it will overwrite its value with the given input.
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.
I'm using the code below to either increment or insert a value in a dictionary. If the key I'm incrementing doesn't exist I'd like to set its value to 1.
public void IncrementCount(Dictionary<int, int> someDictionary, int id)
{
int currentCount;
if (someDictionary.TryGetValue(id, out currentCount))
{
someDictionary[id] = currentCount + 1;
}
else
{
someDictionary[id] = 1;
}
}
Is this an appropriate way of doing so?
Your code is fine. But here's a way to simplify in a way that doesn't require branching in your code:
int currentCount;
// currentCount will be zero if the key id doesn't exist..
someDictionary.TryGetValue(id, out currentCount);
someDictionary[id] = currentCount + 1;
This relies on the fact that the TryGetValue method sets value to the default value of its type if the key doesn't exist. In your case, the default value of int is 0, which is exactly what you want.
UPD. Starting from C# 7.0 this snippet can be shortened using out variables:
// declare variable right where it's passed
someDictionary.TryGetValue(id, out var currentCount);
someDictionary[id] = currentCount + 1;
As it turns out it made sense to use the ConcurrentDictionary which has the handy upsert method: AddOrUpdate.
So, I just used:
someDictionary.AddOrUpdate(id, 1, (id, count) => count + 1);
Here's a nice extension method:
public static void Increment<T>(this Dictionary<T, int> dictionary, T key)
{
int count;
dictionary.TryGetValue(key, out count);
dictionary[key] = count + 1;
}
Usage:
var dictionary = new Dictionary<string, int>();
dictionary.Increment("hello");
dictionary.Increment("hello");
dictionary.Increment("world");
Assert.AreEqual(2, dictionary["hello"]);
Assert.AreEqual(1, dictionary["world"]);
It is readable and the intent is clear. I think this is fine. No need to invent some smarter or shorter code; if it doesn't keep the intent just as clear as your initial version :-)
That being said, here is a slightly shorter version:
public void IncrementCount(Dictionary<int, int> someDictionary, int id)
{
if (!someDictionary.ContainsKey(id))
someDictionary[id] = 0;
someDictionary[id]++;
}
If you have concurrent access to the dictionary, remember to synchronize access to it.
Just some measurements on .NET 4 for integer keys.
It's not quite an answer to your question, but for the sake of completeness I've measured the behavior of various classes useful for incrementing integers based on integer keys: simple Array, Dictionary (#Ani's approach), Dictionary (simple approach), SortedDictionary (#Ani's approach) and ConcurrentDictionary.TryAddOrUpdate.
Here is the results, adjusted by 2.5 ns for wrapping with classes instead of direct usage:
Array 2.5 ns/inc
Dictionary (#Ani) 27.5 ns/inc
Dictionary (Simple) 37.4 ns/inc
SortedDictionary 192.5 ns/inc
ConcurrentDictionary 79.7 ns/inc
And that's the code.
Note that ConcurrentDictionary.TryAddOrUpdate is three times slower than Dictionary's TryGetValue + indexer's setter. And the latter is ten times slower than Array.
So I would use an array if I know the range of keys is small and a combined approach otherwise.
Here is a handy unit test for you to play with concerning ConcurrentDictionary and how to keep the values threadsafe:
ConcurrentDictionary<string, int> TestDict = new ConcurrentDictionary<string,int>();
[TestMethod]
public void WorkingWithConcurrentDictionary()
{
//If Test doesn't exist in the dictionary it will be added with a value of 0
TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue+1);
//This will increment the test key value by 1
TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue+1);
Assert.IsTrue(TestDict["Test"] == 1);
//This will increment it again
TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue+1);
Assert.IsTrue(TestDict["Test"] == 2);
//This is a handy way of getting a value from the dictionary in a thread safe manner
//It would set the Test key to 0 if it didn't already exist in the dictionary
Assert.IsTrue(TestDict.GetOrAdd("Test", 0) == 2);
//This will decriment the Test Key by one
TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue-1);
Assert.IsTrue(TestDict["Test"] == 1);
}
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}]