Hashtable retrieve value by position? - c#

public static Hashtable Drinks = new Hashtable();
Drinks["Water"] = 3;
Drinks["Coffee"] = 2
Drinks["Beer"] = 5;
To get the value of item I use:
int drink = (int)Drinks["Water"];
which works.
I wanted to know how i can make this work.
pCardValue1 = (int)card[1];
Like instead of typing the item name i want to get the value by position.

The Hashtable (and Dictionary) class is not ordered, meaning, it's entries don't have any order or position, and even if you get a list of keys, the order is random. If you want to get values by key and position as well, you should use the OrderedDictionary collection.

You need a OrderedDictionary. HashTable is not ordered.
Also note that HashTable should not be used in production code from framework 2.0, there is a Dictionary<TKey,TValue> class in System.Collections.Generic namespace which is a replacement for HashTable and provides generics.

As already mentioned, you should use OrderedDictionary. Since you asked for an example in the comments, here is one:
var stringKey = "stringKey";
var stringValue = "stringValue";
var objectKey = "dateTimeKey";
var objectValue = DateTime.Now;
var dict = new OrderedDictionary();
dict.Add(stringKey, stringValue);
dict.Add(objectKey, objectValue);
for (int i = 0; i < dict.Count; i++)
{
var value = dict[i];
}
Enumerating the dictionary several times will return the results in the same order. Note that since it accepts an Object for both key and value, you can mix different types as much as you want, meaning you have to be careful when you use the structure.

you can use linq trick to get item name at position.
int position = 1;
var a1 = (from DictionaryEntry entry in Drinks select entry.Key).Skip(position).FirstOrDefault();
If you want item name by value then use
object value = 2;
var a = (from DictionaryEntry entry in Drinks where entry.Value.Equals(value) select entry.Key).FirstOrDefault();

Related

Do Dictionary.Keys.ToArray() and Dictionary.Values.ToArray() preserve ordering?

I have a dictionary of city-population objects:
var cityPopulation = new new Dictionary<string, int>()
{
["Sacramento"] = 495234,
["Miami"] = 453579,
["Memphis"] = 652717
});
I need to get 2 corresponding (same order) arrays. Can I be sure that when I do
var cities = cityPopulation.Keys.ToArray();
var populations = cityPopulation.Values.ToArray();
Order of both arrays will be preserved - i.e.:
cities - 1st element will be Sacramento, 2nd - Miami and 3rd - Memphis, and for array of populations - 1st - 495234, 2nd - 453579 and 3rd - 652717 correspondingly (array of cities should correspond to the array of populations).
How can I be sure about this, and if not - how do I preserve the order of those arrays?
No. Dictionary<TKey, TValue> does not preserve ordering.
For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair<TKey, TValue> structure representing a value and its key. The order in which the items are returned is undefined.
From Dictionary<TKey, TValue> Class on MSDN
For Keys and Value properties documentation says their order is not specified, but it's consistent between the two:
The order of the values in the Dictionary<TKey, TValue>.ValueCollection is unspecified, but it is the same order as the associated keys in the Dictionary<TKey, TValue>.KeyCollection returned by the Keys property.
From Dictionary<TKey, TValue>.Values Property on MSDN
No, they don't "preserve order." Or, to be more precise, they do preserve order, but a dictionary isn't ordered to begin with.
That being said, it looks like your actual requirement is to produce two arrays that contain the items found in the dictionary and also correlate with one another. Such an arrangement is known as parallel arrays.
To make this happen, you just need to create an enumeration that is sorted deterministically (doesn't matter by what, but the key is a pretty obvious candidate, since it is guaranteed to be unique). Once you have a sorted list, just select the keys and values into their own arrays.
var sortedPopulation = cityPopulation.OrderBy( a => a.Key );
string[] cities = sortedPopulation.Select( a => a.Key ).ToArray();
int[] populations = sortedPopulation.Select( a => a.Value ).ToArray();
This should give you the two arrays you need, with elements aligned, even if they are not in the "original sort order" (which technically doesn't even exist).
Full example:
public static void Main()
{
var cityPopulation = new Dictionary<string, int>
{
{"Sacramento",495234 },
{"Miami", 453579 },
{"Memphis", 652717 }
};
var sortedPopulation = cityPopulation.OrderBy( a => a.Key );
string[] cities = sortedPopulation.Select( a => a.Key ).ToArray();
int[] populations = sortedPopulation.Select( a => a.Value ).ToArray();
foreach (var c in cities)
Console.WriteLine(c);
foreach (var p in populations)
Console.WriteLine(p);
}
Output:
Memphis
Miami
Sacramento
652717
453579
495234
If for some reason you would like to get the results without sorting and without enumerating the original list twice, you could also do something like this:
public static void SplitDictionary<T1, T2>(Dictionary<T1, T2> input, out T1[] keys, out T2[] values)
{
keys = new T1[input.Count];
values = new T2[input.Count];
int i = 0;
foreach ( var entry in input )
{
keys[i] = entry.Key;
values[i++] = entry.Value;
}
}
This works because, even though the dictionary can't be relied on for its order, we retrieve the key and value at the same time. Once they are retrieved and put into an array, their order is fixed.
See my code on DotNetFiddle
A dictionary is non-deterministic. There is no implicit ordering of hashtables. In short do not rely on the order being the same as when you added the values.
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.
You can read more here

List<Tuple> has no setter error

I've List Tuple with int and string in it, each time I add new position to this list, I check for the same string in already added elements. Once I see the same - the goal is to change int (to do +1). For example if we have (3, box; 1, apple; 2, PC) and we need to add "apple", so I must change existing "1, apple" to "2, apple".
But I can't do it because Item1 return error "The property has no setter".
Where my mistake?
Thanks.
string[] elements = s.Split(); // Contains all elements as strings.
List<Tuple<int, string>> elementsList = new List<Tuple<int, string>>();
var sortItems = elementsList.OrderBy(x => x.Item1);
for (int i = 0; i < elements.Length; i++)
{
foreach (var item in sortItems)
{
if (Equals(item.Item1, elements[i]))
{
item.Item1 += 1;
}
}
elementsList.Add(new Tuple<int, string>(1, elements[i]));
}
return elementsList;
According to the documentation of Tuple<T1,T2>, the properties cannot be written, which basically means that tuples are immutable. It is impossible to modify its contents in-place; it is necessary to create a new tuple.
Tuple<T1, T2> does not allow you to modify the values inside because it is immutable. Instead try using a Dictionary
string[] elements = s.Split(); // Contains all elements as strings.
IDictionary<string, int> elementsMap = new Dictionary<string, int>();
for (int i = 0; i < elements.Length; i++)
{
string name = elements[i];
if (elementsMap.ContainsKey(name))
{
elementsMap[name] += 1;
}
else
{
elementsMap.Add(name, 1);
}
}
return elementsMap;
Or through Linq(credit to Jeppe Stig Nielsen):
var elementsMap = elements.GroupBy(e => e).ToDictionary(g => g.Key, g => g.Count());
Tuples are immutable types, so basically they are not intented to be changed and have no setter. The reasons got listed up here : Why Tuple's items are ReadOnly?
Either you create a new tuple (as Codor suggested) or you just create your own implementation, like shown here: Why a Tuple, or a KeyValueItem, don't have a setter?
Tuple class is immutable which means its properties do no have public setters to overwrite the underlying value.
Tuples are not meant to be used in a key-value manner, which is probably closer to what you are trying to achieve. Tuples are more suitable for pairing - well they are could be used for more than 2 practically - two correlated pieces of data, such as coordinates for example, or width and height.
More examples in the answers of the link below :
Practical example where Tuple can be used in .Net 4.0?
When should you use a Dictionary ?
Simply when you are doing lookups by a certain unique key to read/modify the an object(which could be a collection it self) corresponding to that key. a quick google around would show you tons of uses.

How to access a Dictionary values within a list by a class object?

I've a class like as below:
public class Source
{
...
...
public List<Dictionary<int, int>> blanks { get; set; }
}
I've created an object of this and a Dictionary for it. I filled 'dic' Dictionary. Then, I add this dic to the blanks list.
Source src = new Source();
Dictionary<int, int> dic = new Dictionary<int, int>();
dic.Add(30, 50);
dic.Add(40, 60);
src.blanks.Add(dic);
And I try to access these 'Key' and 'Value' elements. But, I can't.
int a = src.blanks[0].Key;
int b = src.blanks[0].Value;
What can I do to access these elements?
Thanks.
src.blanks[0] is a whole dictionary, not a single KeyValuePair<int,int>. That is why you cannot access a .Key or .Value on it - there are potentially many keys, and many values associated with them.
You can access all key-value pairs in a dictionary at position zero by enumerating them, like this:
foreach (var kvp in src.blanks[0]) {
int a = kvp.Key;
int b = kvp.Value;
Console.WriteLine("Key:{0} Value:{1}", a, b);
}
blanks[0] returns a Dictionary<int, int>, you need to specify key of your item.
src.blanks[0][key]
Or loop through your values:
foreach(var pair in src.blanks[0])
{
int currentKey = pair.Key;
int currentValue = pair.Value;
}
You are trying to access a dictionary in the list which has no Key property. The Keyvaluepairs in a dictionary have keys.
So assuming you want to look into the first dictionary in the list:
Dictionary<int, int> dict = s.blanks[0];
// lookup 30:
int value = dict[30]; // 40
to get the value you should first index the list and then index the dictionary
to get value
int b = (src.blanks[0])[0]
You want something like the following:
var listItem = src.blanks[0];
var dictionaryItem = listItem[0];
var a = dictionaryItem.Key;
var b = dictionaryItem.Value;
Nevertheless, i advice you to get rid of those "nested generics" List<Dictionary<..,..>. You won't be able to distinguish what kind of object you're dealing with if you use these nested structs.
Use other structs that better represent your business logic. For example, you could derive your own class from List

Problems with Lists and Dictionaries

I'm having a problem with a Dictionary of Lists for both the Key and Value.
My dictionary is set up as this
Dictionary<List<string>,List<double>> f = new Dictionary<List<string>,List<double>>();
(it's like this for a very specific reason).
My problem is how to get the two lists out into their own lists. I have tried the following
List<string> s = new List<string>(f.Keys);
List<string> s = f.Select(kvp=>kvp.Keys).ToList()
List<string> s = f.Select(kvp=>kvp.Keys);
List<string> s = f.Keys;
as well as a variant using IEnumerable. No matter what I do, I can't seem to retrieve the Keys (or using f.Values, the values).
Any help here would be appreciated.
A list of strings seems like a VERY odd key for a dictionary, and will have complexities of its own, but you seem confident that it's correct, so I'll focus on your actual question.
Since Keys is a collection of key values, each of which is a List<string>, any of these should work:
List<List<string>> s = f.Select(kvp=>kvp.Key).ToList();
List<List<string>> s = f.Keys.ToList();
If you want ALL strings as a single list (essentially joining all of the lists together), you can use:
List<string> s2 = f.SelectMany(kvp => kvp.Key).ToList();
The SelectMany essentially selects each item from the collection within each key across the whole dictionary.
Lol This is probably the funniest thing I've seen in a while.
Alright. In c# there is a structure called KeyValuePair<TKey, TValue>. You can then iterate through the entire dataset with foreach and get access to what you want.
foreach(KeyValuePair<<List<string>,List<double>> item in f) {
List<string> key = item.key;
List<double> value = item.value;
}
If you have only 1 key,meaning 1 list of strings:
List<string> newf = f.Keys.ElementAt(0);
If you have more place another index.
Or check if the list as some item so that would be the list to retrieve:
List<string> newf = f.Keys.Single(k => k.Contains("SomeString"));
//this must exist or it will throw exception.
Get a key by checking if the corresponding values sum is above(or less,or equal...)
var newf1 = f.Where(k => k.Value.Sum() > 10).Select(v => v.Key);

how to add an associative index to an array. c#

i have an array of custom objects. i'd like to be able to reference this array by a particular data member, for instance myArrary["Item1"]
"Item1" is actually the value stored in the Name property of this custom type and I can write a predicate to mark the appropriate array item. However I am unclear as to how to let the array know i'd like to use this predicate to find the array item.
I'd like to just use a dictionary or hashtable or NameValuePair for this array, and get around this whole problem but it's generated and it must remain as CustomObj[]. i'm also trying to avoid loading a dictionary from this array as it's going to happen many times and there could be many objects in it.
For clarification
myArray[5] = new CustomObj() // easy!
myArray["ItemName"] = new CustomObj(); // how to do this?
Can the above be done? I'm really just looking for something similar to how DataRow.Columns["MyColumnName"] works
Thanks for the advice.
What you really want is an OrderedDictionary. The version that .NET provides in System.Collections.Specialized is not generic - however there is a generic version on CodeProject that you could use. Internally, this is really just a hashtable married to a list ... but it is exposed in a uniform manner.
If you really want to avoid using a dictionary - you're going to have to live with O(n) lookup performance for an item by key. In that case, stick with an array or list and just use the LINQ Where() method to lookup a value. You can use either First() or Single() depending on whether duplicate entries are expected.
var myArrayOfCustom = ...
var item = myArrayOfCustom.Where( x => x.Name = "yourSearchValue" ).First();
It's easy enough to wrap this functionality into a class so that external consumers are not burdened by this knowledge, and can use simple indexers to access the data. You could then add features like memoization if you expect the same values are going to be accessed frequently. In this way you could amortize the cost of building the underlying lookup dictionary over multiple accesses.
If you do not want to use "Dictionary", then you should create class "myArrary" with data mass storage functionality and add indexers of type "int" for index access and of type "string" for associative access.
public CustomObj this [string index]
{
get
{
return data[searchIdxByName(index)];
}
set
{
data[searchIdxByName(index)] = value;
}
}
First link in google for indexers is: http://www.csharphelp.com/2006/04/c-indexers/
you could use a dictionary for this, although it might not be the best solution in the world this is the first i came up with.
Dictionary<string, int> d = new Dictionary<string, int>();
d.Add("cat", 2);
d.Add("dog", 1);
d.Add("llama", 0);
d.Add("iguana", -1);
the ints could be objects, what you like :)
http://dotnetperls.com/dictionary-keys
Perhaps OrderedDictionary is what you're looking for.
you can use HashTable ;
System.Collections.Hashtable o_Hash_Table = new Hashtable();
o_Hash_Table.Add("Key", "Value");
There is a class in the System.Collections namespace called Dictionary<K,V> that you should use.
var d = new Dictionary<string, MyObj>();
MyObj o = d["a string variable"];
Another way would be to code two methods/a property:
public MyObj this[string index]
{
get
{
foreach (var o in My_Enumerable)
{
if (o.Name == index)
{
return o;
}
}
}
set
{
foreach (var o in My_Enumerable)
{
if (o.Name == index)
{
var i = My_Enumerable.IndexOf(0);
My_Enumerable.Remove(0);
My_Enumerable.Add(value);
}
}
}
}
I hope it helps!
It depends on the collection, some collections allow accessing by name and some don't. Accessing with strings is only meaningful when the collection has data stored, the column collection identifies columns by their name, thus allowing you to select a column by its name. In a normal array this would not work because items are only identified by their index number.
My best recommendation, if you can't change it to use a dictionary, is to either use a Linq expression:
var item1 = myArray.Where(x => x.Name == "Item1").FirstOrDefault();
or, make an extension method that uses a linq expression:
public static class CustomObjExtensions
{
public static CustomObj Get(this CustomObj[] Array, string Name)
{
Array.Where(x => x.Name == Name).FirstOrDefault();
}
}
then in your app:
var item2 = myArray.Get("Item2");
Note however that performance wouldn't be as good as using a dictionary, since behind the scenes .NET will just loop through the list until it finds a match, so if your list isn't going to change frequently, then you could just make a Dictionary instead.
I have two ideas:
1) I'm not sure you're aware but you can copy dictionary objects to an array like so:
Dictionary dict = new Dictionary();
dict.Add("tesT",40);
int[] myints = new int[dict.Count];
dict.Values.CopyTo(myints, 0);
This might allow you to use a Dictionary for everything while still keeping the output as an array.
2) You could also actually create a DataTable programmatically if that's the exact functionality you want:
DataTable dt = new DataTable();
DataColumn dc1 = new DataColumn("ID", typeof(int));
DataColumn dc2 = new DataColumn("Name", typeof(string));
dt.Columns.Add(dc1);
dt.Columns.Add(dc2);
DataRow row = dt.NewRow();
row["ID"] = 100;
row["Name"] = "Test";
dt.Rows.Add(row);
You could also create this outside of the method so you don't have to make the table over again every time.

Categories

Resources