How can I retreive elemenents in Dictionary through index (int index )..;Instead of a key
foreach(KeyValuePair<String,String> pair in dictionary)
{
string key = pair.Key;
string value = pair.Value;
}
or to get access by item
dictionary.ToList()[index].Key/Value :-)
Dictionary is an unordered collection so it does not provide random access. Only types that implement IList<T> provide random access to their contents.
Well, that's not totally correct - you could use a OrderedDictionary (which would give you random access without IList<T>) but you lose the benefits of the generic dictionary. If you need random access, most likely you shouldn't be using a Dictionary.
check out following
Accessing a Dictionary.Keys Key through a numeric index
There is no method for retrieving elements by index because the Dictionary class does not specify the order in which key/value pairs are stored. If you need both key and index lookup use the OrderedDictionary class.
I found this useful:
foreach (var key in dictionary.Keys)
{
var value = dictionary[key];
}
or
foreach (var value in dictionary.Values)
{
// use value
}
Related
I need to do currentKey+1. So i would like to find the index of the key value and get the next key (or first if at end). How do i find the current index of the key?
I am using a Dictionary<int, classname> and i looked for .Find or IndexOf with Linq to no avail.
Dictionaries are not sorted, so the Key doesn't have any index really. See my question here: Accessing a Dictionary.Keys Key through a numeric index
Use an OrderedDictionary which has an indexer that takes an Int.
Edit: 'm not really sure I understand what you want. If you want to iterate through a Dictionary, just use
foreach(KeyValuePair kvp in yourDict)
If the key is an Int and you want the next, use
var newkey = oldkey+1;
if(yourdict.ContainsKey(newkey)){
var newvalue = yourdict[newkey];
}
If the ints are not sequential, you can use
var upperBound = d.Max(kvp => kvp.Key)+1; // to prevent infinite loops
while(!yourdict.ContainsKey(newkey) && newkey < upperBound) {
newkey++;
}
or, alternatively:
var keys = (from key in yourdict.Keys orderby key select key).ToList();
// keys is now a list of all keys in ascending order
As Michael Stum noted, Dictionary<TKey, TValue> is not sorted (it's a hashtable) so there is no such thing as the "index" of a key. Instead, you can use SortedList which is (as the name implies) sorted and does provide an IndexOfKey method.
Be aware that the performance characteristics of Dictionary<TKey, TValue> is different to SortedList<TKey, TValue> though. While Dictionary is O(1) for inserts and deletes, SortedList is O(logn).
Without using a different collection it could be done like this. Though I'm not sure how efficient this is.
classIndex = classes.ToList().IndexOf(new KeyValuePair<int, classname>(newKey, classes[newKey]));
What I need is something like an array but letting me to assign an element to whatever an index at any time and check if there is already a value assigned to particular index approximately like
MyArray<string> a = new MyArray<string>();
a[10] = "ten";
bool isTheFifthElementDefined = a[5] != null; // false
Perhaps Dictionary<int, string> with its ContainsKey method could do, but isn't there a more appropriate data structure if I want an ordered collection with numeric keys only?
I am also going to need to iterate through the defined elements (with foreach or linq preferably) accessing both the value and the key of current element.
As you mentioned Dictionary seems more appropriate for this.But you can do it with generic lists,for example, when you are creating your list you can specify an element count,and you can give a default temporary value for all your elements.
List<string> myList = new List<string>(Enumerable.Repeat("",5000));
myList[2300] = "bla bla bla..";
For int:
List<int> myList = new List<int>(Enumerable.Repeat(0,5000));
For custom type:
List<MyClass> myList = new List<MyClass>(Enumerable.Repeat(new MyClass(), 100));
Ofcourse It is not the best solution...
Note: Also you can use SortedList instead of Dictionary if you want an ordered collection by keys:
SortedList<TKey, TValue> : Represents a collection of key/value pairs that are sorted by key based on the associated IComparer implementation.
If you need key/value pairs you cannot use a list, you'll need a Dictionary.
The implementation is pretty snappy so don't be too afraid about performance (as long as you don't put too much values in it).
You can iterate over it with
foreach(KeyValuePair<int, string> kvp in dict)
{
}
If you need to order it you can use a list:
List<int> ordered = new List(dict.Keys);
ordered.Sort();
foreach(int key in ordered)
{
}
There is a SortedList
slLanguage = new SortedList();
slLanguage.Add("Bahasa","id-ID");
slLanguage.Add("Chinese Simplified(中文简体)","zh-CN");
slLanguage.Add("Chinese Traditional(中文繁體)","zh-TW");
slLanguage.Add("Kazakh","kk-KZ");
slLanguage.Add("Russian(русский)","ru-RU");
slLanguage.Add("Vietnamese(Việt)","vi-VN");
slLanguage.Add("English", "en-US");
How can I get the key by value?
For example: Get the item key "zh-CN"
If you would like to get the key from a value, you may use SortedList.IndexOfValue(object value) to get the index of the value you specify. Then, use SortedList.GetKey(int index) to return a key as object from the value's index we just gathered.
Example
SortedList slLanguage = new SortedList(); //Initializes a new SortedList of name slLanguage
//Add the keys and their values to the list
slLanguage.Add("Bahasa", "id-ID");
slLanguage.Add("Chinese Simplified(中文简体)", "zh-CN");
slLanguage.Add("Chinese Traditional(中文繁體)", "zh-TW");
slLanguage.Add("Kazakh", "kk-KZ");
slLanguage.Add("Russian(русский)", "ru-RU");
slLanguage.Add("Vietnamese(Việt)", "vi-VN");
slLanguage.Add("English", "en-US");
//
object returnedKey = slLanguage.GetKey(slLanguage.IndexOfValue("zh-CN")); //Gets the key from zh-CN as returnedKey of type object
Thanks,
I hope you find this helpful :)
There's probably a better way to do this, but here's one way to do it:
int index = slLanguage.IndexOfValue("zh-CN");
var item = slLanguage.GetKey(index);
Looking the key from Value would be not efficient and defeats the purpose of sorted List. Sorted list is really a sorted Dictionary named confusingly as SortedList.
I use this:
foreach(KeyValuePair<String,String> entry in MyDic)
{
// do something with entry.Value or entry.Key
}
The problem is that I can't change the value of entry.Value or entry.Key
My question is that how can i change the value or key when looping through a dictionary?
And, does dictionary allow duplicated key? And if yes, how can we avoid ?
Thank you
You cannot change the value of a dictionary entry while looping through the items in the dictionary, although you can modify a property on the value if it's an instance of a reference type.
For example,
public class MyClass
{
public int SomeNumber { get; set;}
}
foreach(KeyValuePair<string, MyClass> entry in myDict)
{
entry.Value.SomeNumber = 3; // is okay
myDict[entry.Key] = new MyClass(); // is not okay
}
Trying to modify a dictionary (or any collection) while looping through its elements will result in an InvalidOperationException saying the collection was modified.
To answer your specific questions,
My question is that how can i change the value or key when looping through a dictionary?
The approach to both will be pretty much the same. You can either loop over a copy of the dictionary as Anthony Pengram said in his answer, or you can loop once through all the items to figure out which ones you need to modify and then loop again through a list of those items:
List<string> keysToChange = new List<string>();
foreach(KeyValuePair<string, string> entry in myDict)
{
if(...) // some check to see if it's an item you want to act on
{
keysToChange.Add(entry.Key);
}
}
foreach(string key in keysToChange)
{
myDict[key] = "new value";
// or "rename" a key
myDict["new key"] = myDict[key];
myDict.Remove(key);
}
And, does dictionary allow duplicated key? And if yes, how can we avoid ?
A dictionary does not allow duplicate keys. If you want a collection of <string, string> pairs that does, check out NameValueCollection.
Updating the dictionary in the loop is going to be a problem, as you cannot modify the dictionary as it is being enumerated. However, you can work around this pretty easily by converting the dictionary to a list of KeyValuePair<> objects. You enumerate that list, and then you can modify the dictionary.
foreach (var pair in dictionary.ToList())
{
// to update the value
dictionary[pair.Key] = "Some New Value";
// or to change the key => remove it and add something new
dictionary.Remove(pair.Key);
dictionary.Add("Some New Key", pair.Value);
}
For the second part, the key in a dictionary must be unique.
KeyValuePair's Key and value are read only. But you can change a value like that:
dictionary[key].Value = newValue;
But if you want to change the key, you will have to remove/add a key.
And no, a Dictionary does not allow duplicate keys, it will throw an ArgumentException.
You cannot modify keys while enumerating them.
One method I use for changes to the collection while enumerating them is that I do break; out of the foreach loop when a match is found and item is modified, and am restarting the whole enumeration all over again. That's one way of handling it...
No, Dictionary can't have duplicate keys. If you want something that will sort by key and allow duplicates, you should use some other data structure.
You can do this like
for (int i = 0; i < MyDic.Count; i++)
{
KeyValuePair<string, string> s = MyDic.ElementAt(i);
MyDic.Remove(s.Key);
MyDic.Add(s.Key, "NewValue");
}
And Dictionary doesn't allow duplicates
I would like to know if some property or method exists that gets the index of a specific value.
I found that dictionaries have the Contains() method which returns true if the value passed in exists, so this method almost implements what I need.
I know that I can loop through all the value pairs and check the condition, but I ask because maybe there's an optimized way of doing this.
Let's say you have a Dictionary called fooDictionary
fooDictionary.Values.ToList().IndexOf(someValue);
Values.ToList()
converts your dictionary values into a List of someValue objects.
IndexOf(someValue)
searches your new List looking for the someValue object in question
and returns the Index which would match the index of the Key/Value pair in the dictionary.
This method does not care about the dictionary keys, it simply returns the index of the value that you are looking for.
This does not however account for the issue that there may be several matching "someValue" objects.
There's no such concept of an "index" within a dictionary - it's fundamentally unordered. Of course when you iterate over it you'll get the items in some order, but that order isn't guaranteed and can change over time (particularly if you add or remove entries).
Obviously you can get the key from a KeyValuePair just by using the Key property, so that will let you use the indexer of the dictionary:
var pair = ...;
var value = dictionary[pair.Key];
Assert.AreEqual(value, pair.Value);
You haven't really said what you're trying to do. If you're trying to find some key which corresponds to a particular value, you could use:
var key = dictionary.Where(pair => pair.Value == desiredValue)
.Select(pair => pair.Key)
.FirstOrDefault();
key will be null if the entry doesn't exist.
This is assuming that the key type is a reference type... if it's a value type you'll need to do things slightly differently.
Of course, if you really want to look up values by key, you should consider using another dictionary which maps the other way round in addition to your existing dictionary.
Consider using System.Collections.Specialized.OrderedDictionary, though it is not generic, or implement your own (example).
OrderedDictionary does not support IndexOf, but it's easy to implement:
public static class OrderedDictionaryExtensions
{
public static int IndexOf(this OrderedDictionary dictionary, object value)
{
for(int i = 0; i < dictionary.Count; ++i)
{
if(dictionary[i] == value) return i;
}
return -1;
}
}
You can find index by key/values in dictionary
Dictionary<string, string> myDictionary = new Dictionary<string, string>();
myDictionary.Add("a", "x");
myDictionary.Add("b", "y");
int i = Array.IndexOf(myDictionary.Keys.ToArray(), "a");
int j = Array.IndexOf(myDictionary.Values.ToArray(), "y");
You can use LINQ to help you with this.
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "hi");
dict.Add(2, "NotHi");
dict.Add(3, "Bah");
var item = (from d in dict
where d.Value == "hi"
select d.Key).FirstOrDefault();
Console.WriteLine(item); //Prints 1
If searching for a value, you will have to loop through all the data. But to minimize code involved, you can use LINQ.
Example:
Given Dictionary defined as following:
Dictionary<Int32, String> dict;
You can use following code :
// Search for all keys with given value
Int32[] keys = dict.Where(kvp => kvp.Value.Equals("SomeValue")).Select(kvp => kvp.Key).ToArray();
// Search for first key with given value
Int32 key = dict.First(kvp => kvp.Value.Equals("SomeValue")).Key;
In your comment to max's answer, you say that what you really wanted to get is the key in, and not the index of, the KeyValuePair that contains a certain value. You could edit your question to make it more clear.
It is worth pointing out (EricM has touched upon this in his answer) that a value might appear more than once in the dictionary, in which case one would have to think which key he would like to get: e.g. the first that comes up, the last, all of them?
If you are sure that each key has a unique value, you could have another dictionary, with the values from the first acting as keys and the previous keys acting as values. Otherwise, this second dictionary idea (suggested by Jon Skeet) will not work, as you would again have to think which of all the possible keys to use as value in the new dictionary.
If you were asking about the index, though, EricM's answer would be OK. Then you could get the KeyValuePair in question by using:
yourDictionary.ElementAt(theIndexYouFound);
provided that you do not add/remove things in yourDictionary.
PS: I know it's been almost 7 years now, but what the heck. I thought it best to formulate my answer as addressing the OP, but of course by now one can say it is an answer for just about anyone else but the OP. Fully aware of that, thank you.
no , there is nothing similar IndexOf for Dictionary although you can make use of ContainsKey method to get whether a key belongs to dictionary or not