I read here that SortedDictionary does not allow indexed retrieval unlike SortedList.
Then how can I get the nameAddr["C"] correctly in the following code snippet?
SortedDictionary<string, string> nameAddr = new SortedDictionary<string, string>();
nameAddr.Add("X", "29");
nameAddr.Add("A", "30");
nameAddr.Add("C", "44");
Console.WriteLine(nameAddr["C"]);
That's indexing by key. SortedList allows indexing by "index of key", e.g. nameAddr.Values[1] would return "44".
(The collection doesn't allow indexing of name/value pair, just of each of Keys and Values separately.)
For example:
var list = new SortedList<string, string>
{
{ "X", "29" },
{ "A", "30" },
{ "C", "44" },
};
Console.WriteLine(list.Keys[1]); // Prints "C"
Console.WriteLine(list.Values[1]); // Prints "44"
SortedList internally uses an array as the data structure for storage and then just sorts the array as needed to keep the items in order. Since it uses an array the items can be accessed using a numeric index like you would for any array.
SortedDictionary internally uses a red-black binary search tree to keep the items in order. The concept is completely different. There is no array and no analog for retrieving the items by a numeric index. Your only option is to use the key portion of the key-value pair that was added to the dictionary.
With that said. Your code looks correct to me. That is the only way to retrieve items from the dictionary (other than using than Values collection, but that will not give you the numeric indexing ability either).
Related
I know how to make a new dictionary case insensitive with the code below:
var caseInsensitiveDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
But I'm using WebApi which serializes JSON objects into a class we've created.
public class Notification : Common
{
public Notification();
[JsonProperty("substitutionStrings")]
public Dictionary<string, string> SubstitutionStrings { get; set; }
}
So besides rebuilding the dictionary after receiving the "Notification" object, is there a way to set this dictionary to case insensitive in the first place or after it's been created?
Thanks
So besides rebuilding the dictionary after receiving the "Notification" object, is there a way to set this dictionary to case insensitive in the first place or after it's been created?
No, it is impossible. You need to create a new dictionary.
Currently the dictionary has all of the keys in various different buckets; changing the comparer would mean that a bunch of keys would all suddenly be in the wrong buckets. You'd need to go through each key and re-compute where it needs to go and move it, which is basically the same amount of work as creating a new dictionary would be.
Whenever an item is added to a dictionary, the dictionary will compute its hash code and make note of it. Whenever a dictionary is asked to look up an item, the dictionary will compute the hash code on the item being sought and assume that any item in the dictionary which had returned a different hash code cannot possibly match it, and thus need not be examined.
In order for a dictionary to regard "FOO", "foo", and "Foo" as equal, the hash code function it uses must yield the same value for all of them. If a dictionary was built using a hash function which returns different values for "FOO", "foo", and "Foo", changing to a hash function which yielded the same value for all three strings would require that the dictionary re-evaluate the hash value of every item contained therein. Doing this would require almost as much work as building a new dictionary from scratch, and for that reason .NET does not support any means of changing the hash function associated with a dictionary other than copying all the items from the old dictionary to a new dictionary, abandoning the old one.
Note that one could design a SwitchablyCaseSensitiveComparator whose GetHashCode() method would always return a case-insensitive hash value, but whose Equals method could be switched between case-sensitive and non-case sensitive operation. If one were to implement such a thing, one could add items to a dictionary and then switch between case-sensitive and non-case-sensitive modes. The biggest problem with doing that would be that adding if the dictionary is in case-sensitive mode when two items are added which differ only in case, attempts to retrieve either of those items when the dictionary is in case-insensitive mode might not behave as expected. If populating a dictionary in case-insensitive mode and performing some look-ups in case-sensitive mode should be relatively safe, however.
Try changing your class definition to something like this
public class Notification : Common
{
public Notification()
{
this.substitutionStringsBackingStore =
new Dictionary<string,string>( StringComparer.OrdinalIgnoreCase )
;
}
[JsonProperty("substitutionStrings")]
public Dictionary<string, string> SubstitutionStrings
{
get { return substitutionStringsBackingStore ; }
set { substitutionStringsBackingStore = value ; }
}
private Dictionary<string,string> substitutionStringsBackingStore ;
}
You do have to re-create the dictionary, but this can be done with extensions:
public static class extensions
{
public static Dictionary<string, T> MakeCI<T>(this Dictionary<string, T> dictionary)
{
return dictionary.ToDictionary(kvp => kvp.Key, kvp => kvp.Value, StringComparer.OrdinalIgnoreCase);
}
}
I've specified string type for the key as this is what we want to be CI, but the value can be any type.
You would use it like so:
myDict = myDict.MakeCI();
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)
{
}
using ...
string[] myFiles = Directory.GetFiles(FilePathIn, "*.dat", SearchOption.TopDirectoryOnly);
I am getting a list of files returned. Alongside this I want to keep a set of int flags. I am about to do this by creating a tuple list eg List<Tuple<int, string>> then looping through myfiles adding each to the tuple list.
Although this will work I wondered if there was a cleaner way to do this? It doesn't have to be a tuple list. It just needs to be an ordered list of the files with a flag
If you are interested in just iteration then a list of some compound type is the way to go -- you can use a custom struct instead of a Tuple to increase readability or a custom class if you intend for the flags to be mutable later on, but the general idea is the same.
You can also use a Dictionary<string, int> of filenames to flags; this has the advantage that it allows quick lookups if you have a filename in hand.
Finally, consider using a [Flags] enum instead of a bare integer to hold the flags you need.
Depending on how you want to use the data later, I would either map the filenames to the integers (Dictionary<string, int>) or the integers to files. I assume two files can have the same "flag", so I would use either a Dictionary<int, List<string>> or constuct IGrouping<int, string> or ILookup<int, string>. It's a shame really that .NET BCL doesn't contain a straightforward mutable Multimap (or Lookup) that you could use like a dictionary.
Why you don't use dictionary to access an element in a dictionary it will cost O(1)
Dictionary<int,string> myFilesOrderedDict = new Dictionary<int,string>();
Or if you want to groupfile by an int as a flag you can do the inverse as I don't think that the name of the file can be repeated twice
Something like this
//string will be the name of the file
Dictionary<string ,int> myFilesOrderedDict = new Dictionary<string,int>();
Hope this help
You can create an anonymous type:
var filesWithFlags = Directory.GetFiles(..)
.Select(f => new {File = f, Flags = 123});
And use the result like this:
foreach (var fileWithFlags in filesWithFlags)
{
DoSomethingWith(fileWithFlags.File);
AndDoSomethingWith(fileWithFlags.Flags);
}
I'm wondering if the index of an array can be given a name in C# instead of the default index value. What I'm basically looking for is the C# equivalent of the following PHP code:
$array = array(
"foo" => "some foo value",
"bar" => "some bar value",
);
Cheers.
PHP blends the concept of arrays and the concept of dictionaries (aka hash tables, hash maps, associative arrays) into a single array type.
In .NET and most other programming environments, arrays are always indexed numerically. For named indices, use a dictionary instead:
var dict = new Dictionary<string, string> {
{ "foo", "some foo value" },
{ "bar", "some bar value" }
};
Unlike PHP's associative arrays, dictionaries in .NET are not sorted. If you need a sorted dictionary (but you probably don't), .NET provides a sorted dictionary type.
In an array, no. However, there is the very useful Dictionary class, which is a collection of KeyValuePair objects. It's similar to an array in that it is an iterable collection of objects with keys, but more general in that the key can be any type.
Example:
Dictionary<string, int> HeightInInches = new Dictionary<string, int>();
HeightInInches.Add("Joe", 72);
HeightInInches.Add("Elaine", 60);
HeightInInches.Add("Michael", 59);
foreach(KeyValuePair<string, int> person in HeightInInches)
{
Console.WriteLine(person.Key + " is " + person.Value + " inches tall.");
}
MSDN Documentation for Dictionary<TKey, TValue>
Look at Hashtable in C#. This is the data structure that does what you want in C#.
You could use a Dictionary<string, FooValue> or similar type or collection type or, if you must stick to array, define an Enum with your labels.
When I remove Dictionary key add then add new key to dictionary new value is not added to last location. Instead of its adding in the key where it is removed.
Dictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(1, "a");
dic.Add(2, "b");
dic.Add(3, "c");
dic.Remove(2);
dic.Add(4, "d");
I want output as
1 "a"
3 "c"
4 "d"
Not as
1 "a"
4 "d"
3 "c"
Dictionarys are not guaranteed to be in the order of insertion. SortedDictionarys are:
SortedDictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(1, "a");
dic.Add(2, "b");
dic.Add(3, "c");
dic.Remove(2);
dic.Add(4, "d");
Produces:
1 "a"
3 "c"
4 "d"
Dictionaries do not necessarily preserve ordering. Your either looking for the SortedDictionary class, or should just sort the key value pairs when printing your results.
If you manage the sorting by yourself, you can use a List<KeyValuePair<int, string>>. In a list you use the Insert-method to insert the item at the position you want. The order in the list remains.
From here:
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.
As stated by others, you need a data structure that preserves order such as a SortedDictionary (preserves order by value) or a SortedList (preserves insertion order). (see 4.0 versions here and here and 2.0 versions here and here)
Dictionary is unsorted. (Random access map)
You can use SortedDictionary to keep it sorted by key.
Or if you want to sort by value (not key) check this out:
How do you sort a dictionary by value?