Unexpected issue Copying Dictionaries - c#

My idea was to copy a dictionary while resetting all the values of the previous one, so i have this instruction:
var dic2 = new Dictionary<string, int>(dic.ToDictionary(kvp => kvp.Key, kvp => 0));
However i had an unexpected problem doing this, since the new copied dictionary doesnt have the same order of keys of the previous one.
Any way to reset the values but to maintain the same order of keys? Witouth resorting to some type of sorting?

The answer is not to rely on the order of keys in a Dictionary<,> in the first place. It's emphatically not guaranteed.
This is documented on MSDN, but not nearly as clearly as I'd have wanted:
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.
.NET doesn't currently have an insertion-order-preserving dictionary implementation as far as I'm aware :(

The order of the keys in a Dictionary<K,V> isn't maintained. You might want to use a SortedDictionary<K,V> instead (note that this class sorts the entries based on the key, but doesn't allow an arbitrary order, unless you create a specific key comparer)

.Net dictionaries are unordered.
Your question has no answer.
You should consider using a List<KeyValuePair<string, int>> instead.

Dictionary doesn't define sequence of keys. It is not array or list. You should not rely on order of keys on dictionary. Dictionary was made for by-key access not for sequential.

Related

How to get a partilcular item from a Dictionary object with index?

How to retrive an item from an dictionary object using an Index? eg i have a dicitiory object of 10 items and i have to get the 5th keypairvalue from the dictionary?
Dictionaries are unordered. If you mean "the 5th item added to the dictionary" - they don't provide this functionality.
One thing to be careful of is that in many cases Dictionary<TKey, TValue> appears to be ordered - if you just add a bunch of entries and then iterate, then under the current implementation I believe you will at least usually get back the pairs in the same order. However, it's not guaranteed, it's not meant to happen particularly - it's just a quirk of the implementation. If you delete entries and then add more, then the whole thing goes pear-shaped.
Fundamentally, if you want ordering as well as key lookups, you need to store a list as well as a dictionary.
If you are using .NET 3.5 or greater:
var keyValuePair = d.ElementAt(4);
However, this is using an enumerator behind the scenes and the ordering of enumerated items from a dictionary is not guaranteed:
The IDictionary interface allows the contained keys and values to be enumerated, but it does not imply any particular sort order (From IDictionary reference on MSDN).
This means that the element you get back might not correspond to the order you inserted it in and thus is probably not what you expect.
There is an OrderedDictionary class in System.Collections.Specialized that enforces the ordering and allows you to access by index through the Item indexer. However, this is from the pre-generics days so it only accepts object key-values and thus isn't quite as friendly to work with as the generic collections.
I just found this article on CodeProject that implements a generic OrderedDictionary. I have never used this but it might be useful for you.
Ignoring the fundamental abuse of a dictionary that this question presents:
int counter = 0;
foreach (var pair in yourDictionary)
{
if (++counter == 5)
{
// pair contains your fifth item
}
}
If you're using a generic dictionary like this:
Dicionary<int,string> myDict = new Dictionary<int,string>();
You could pull the 5th value from the dictionary by converting the output to a list:
string SomeString = myDict.Values.ToList()[4];
But typically you'd use a dictionary when you're more concerned about retrieving a value based on a pre-determined key rather than it's position in the list.
The 5th according to which ordering? The Dictionary class does not guarantee any specific ordering. If you want it in some specific ordering, retrieve the pairs from the collection (for example as John suggests) and sort them, then get the KeyValuePair at the index you need. If you need it ordered by insertion order, try using the System.Collections.Specialized.OrderedDictionary instead, then you can access the KeyValuePair directly by index.
Use System.Linq
string item=dicOBj.Keys.ElementAt(index);
you can get both key and value in the same way specifying index
.NET Framework has 8 dictionary classes: Dictionary, Hastable, ListDictionary, OrderedDictionary, SortedDictionary , SortedList, SortedList Generic. In all these classes items can be retrieved by key, but items can be retrieved by index only in OrderedDictionary, SortedList, SortedList Generic. If you need to retrieve from you dictionary items by key or by index you must use one of these classes: OrderedDictionary, SortedList, SortedList Generic.
How to use these classes you can find: OrderedDictionary Class , SortedList Class

Dictionary with Exact Same Keys and Values

I need something like a Dictionary or a SortedList but i keep getting exceptions thrown when it receives two things that are the same... Is there another way around this?
Thanks
My guess is that you're using
dictionary.Add(key, value);
If you're happy just replacing the existing key/value pair, then just use the indexer:
dictionary[key] = value;
If you want to have multiple values for the same key, see the other answers :)
You probably want a multimap. You can simulate one with a Dictionary<Key, List<Value>>. Also see this question, it has some multimap implementations.
The key in a dictionary or a sorted list the key should be unique: that's the purpose of hashtables. You could use List<KeyValuePair<TKey, TValue>> or KeyValuePair<TKey, TValue>[] instead but of course you won't be able to locate a value by key as you may have duplicates.
Both a dictionary and a sortedlist are keyed, meaning that the keys must be unique.
You could check before you add the item, e.g. dic.ContainsKey(key) or list.Contains(item) before adding.
If you would like to be able to add multiple values for a single key you can use a NameValueCollection.
If what you're asking for is a dictionary where the value is the same as the key, then there's a generic collection type named 'HashSet' in the System.Collections.Generic namespace which looks like it serves that purpose.
If you're just asking about an exception generated when adding to your dictionary, I think Jon Skeet is probably right on what is probably your issue.
HashSet:
http://msdn.microsoft.com/en-us/library/bb359438.aspx

Get first key from Dictionary<string, string>

I'm using a System.Collections.Generic.Dictionary<string, string>.
I want to return the first key from this dictionary. I tried dic.Keys[0] but the only thing I have on the Keys property (which is a KeyCollection object) is an enumerator.
Do I have to enumerate through all the keys to get the first one?
Assuming you're using .NET 3.5:
dic.Keys.First();
Note that there's no guaranteed order in which key/value pairs will be iterated over in a dictionary. You may well find that in lots of cases you get out the first key that you put into the dictionaries - but you absolutely must not rely on that. As Skirwan says, there isn't really a notion of "first". Essentially the above will give you "a key from the dictionary" - that's about all that's guaranteed.
(If you don't know whether the dictionary is empty or not, you could use FirstOrDefault.)
The idea of 'first' doesn't really apply to a dictionary, as there's no ordering on the entries; any insert or remove is allowed to radically change the order of the keys.
Firstly, no, you do not have to enumerate all of the entries — just enumerate the first item:
IEnumerator enumerator = dictionary.Keys.GetEnumerator();
enumerator.MoveNext();
object first = enumerator.Current;
Ideally one would check that the MoveNext() actually succeeded (it returns a bool) otherwise the call to Current may throw.
Please also note that the order of a dicitonary is not specified. This means that the 'first' item may in fact be any key, may be different on subsequent calls (though in practice will not) and will certainly change as items are added and removed from the dictionary.
Seems a bit over the top, but how about
foreach (<Type> k in dic.Keys)
return k;
we can using linq technology
var key = dic.Take(1).Select(d => d.Key).First()
or we can use another search
var myList = dic.Take(1).Where(d => d.Key.Contains("Heaven")).ToList();

How to find a 'first' value in a Dictionary?

How can I find the first value in a Dictionary<int, MyTableClass> where MyTableClass inherits Field<F1, F2, F3>? I'd prefer a Property or Property/Method combination that returns the first value in the Dictionary where F1 = MyEnum.value.
What I don't want to do is a foreach. Performance-wise, this is really not a preferred method.
The shortest way to find a value matching some criteria (I couldn't quite understand what you want specifically - first F1 is a generic type parameter, and then you use == to compare it as if it was a value...) is to do this:
dictionary.Values.First(x => ...);
where ... will be a boolean expression on x. However, this will not be any faster than foreach ...because you're not doing a lookup on dictionary key. Only key lookup is fast; for anything else, you have to do a linear scan (or maintain a second dictionary for a different key, which will be whatever you do lookups on). [copied from comment]
No matter how you dress it up here you are going to essentially have to do a foreach over the values in the Dictionary. A Dictionary<TKey,TValue> provides close to O(1) access for a full key to a given value. It is not designed to provide efficient access to a partial key. In order to get that you would need to keep a second Dictionary instance making the appropriate mapping.
The dictionary doesn't maintain any specific order between element, so there isn't really any element that can be the first one unless you specify some ordering.
You can get the first item that the dictionary happens to find like this:
MyTableClass one = dict.Where(pair => pair.Value.F1 == MyEnum.value).First();
This will just loop through the items until it finds a match, so you are just using the dictionary as a list. If you want any performance, you should have a dictionary where the value from F1 is the key.
You could use the .First() extension method.

C# associative array

I've been using a Hashtable, but by nature, hashtables are not ordered, and I need to keep everything in order as I add them (because I want to pull them out in the same order). Forexample if I do:
pages["date"] = new FreeDateControl("Date:", false, true, false);
pages["plaintiff"] = new FreeTextboxControl("Primary Plaintiff:", true, true, false);
pages["loaned"] = new FreeTextboxControl("Amount Loaned:", true, true, false);
pages["witness"] = new FreeTextboxControl("EKFG Witness:", true, true, false);
And when I do a foreach I want to be able to get it in the order of:
pages["date"]
pages["plaintiff"]
pages["loaned"]
pages["witness"]
How can I do this?
I believe that .NET has the OrderedDictionary class to deal with this. It is not generic, but it can serve as a decent Hashtable substitute - if you don't care about strict type safety.
I've written a generic wrapper around this class, which I would be willing to share.
http://msdn.microsoft.com/en-us/library/system.collections.specialized.ordereddictionary.aspx
EDIT: LBushkin is right - OrderedDictionary looks like it does the trick, albeit in a non-generic way. It's funny how many specialized collections there are which don't have generic equivalents :( (It would make sense for Malfist to change the accepted answer to LBushkin's.)
(I thought that...) .NET doesn't have anything built-in to do this.
Basically you'll need to keep a List<string> as well as a Dictionary<string,FreeTextboxControl>. When you add to the dictionary, add the key to the list. Then you can iterate through the list and find the keys in insertion order. You'll need to be careful when you remove or replace items though.
use sorted list i think it will solve your problem
becuase SortedList object internally maintains two arrays to store the elements of the list; that is, one array for the keys and another array for the associated values. Each element is a key/value pair that can be accessed as a DictionaryEntry object
SortedList sl = new SortedList();
foreach(DictionaryEntry x in sl)
{}
Use the KeyedCollection
Its underlying base is a List but provides a dictionary lookup based on key. In this case your key is the strings. So as long as you aren't adding the same key twice you are fine.
http://msdn.microsoft.com/en-us/library/ms132438.aspx
There's no perfect solution before .NET 4.0. In < 3.5 You can:
Use a generic SortedList with integer key-type, and value type of the most-derived common type of your items. Define an integer value (i, let's say) and as you add each item to the SortedList, make the key i++, incrementing it's value as you go. Later, iterate over the GetValueList property of the sorted list. This IList property will yield your objects in the order you put them in, because they will be sorted by the key you used.
This is not lightening-fast, but pretty good, and generic. If you want to also access by key, you need to do something else, but I don't see that in your requirements. If you don't new to retrieve by key, and you add items in key order so the collection doesn't actually have to do its sorting, this is it.
In .NET 4.0 you'll have the generic SortedSet Of T, which will be absolutely perfect for you. No tradeoffs.
The best way is to use the C# indexers. It is configurable to anything we like. We can pass an int, enum, long, double or anything we like.
Just have to create a class and give it indexers and configure input and output parameters. It is a little more work but I think this is the only right way.
Please see this MSDN link for more information how to use it.
See Indexers: http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
One alternative is to keep your ordered key values in an ordered structure like a List, the rest being still stored in a dictionnary.
Then, when you need to access your data, just go through your sorted List and query your dictionnary along the way.
look at sorted list
http://msdn.microsoft.com/en-us/library/system.collections.sortedlist.aspx
As Haxelit suggests, you might derive from KeyedCollection<TKey, TValue>. It actually uses a List underneath until you hit a certain threshold value, and then it maintains both a List and a Dictionary. If you can use a function to derive one of your keys from one of your values, then this is an easy solution. If not, then it gets pretty messy.

Categories