Find a value from a hashtable - c#

If I were having a Generic list I would have done some thing like this
myListOfObject.FindAll(x=>(x.IsRequired==false));
What if I need to do similar stuff in Hashtable? Copying to temporary hashtable and looping and comparing would be that last thing I would try :-(

Firstly, use System.Collections.Generic.Dictionary<TKey, TValue> for better strong-type support as opposed to Hashtable.
If you need to just find one key or one value, use the methods ContainsKey(object key) or ContainsValue(object value), both of which are found on the Hashtable type.
Or you can go further and use linq extensions on the Hashtable parts:
Hashtable t = new Hashtable();
t.Add("Key", "Adam");
// Get the key/value entries.
var itemEntry = t.OfType<DictionaryEntry>().Where(de => (de.Value as string) == "Adam");
// Get just the values.
var items = t.Values.OfType<string>().Where(s => s == "Adam");
// Get just the keys.
var itemKey = t.Keys.OfType<string>().Where(k => k == "Key");

Related

C# Dictionary filtering (LINQ) values and getting the key

I have a dictionary fooDictionary<string, MyObject>.
I am filtering the fooDictionary to get only the MyObject with a specific value of the property.
//(Extension method is a extension method that I made for the lists
//(PS: ExtensionMethod returns only 1x MyObject))
fooDictionary.Values.Where(x=>x.Boo==false).ToList().ExtensionMethod();
But I also want to get the keys of the already filtered MyObject's. How can I do that?
Instead of just pulling the values, query the KeyValuePair
fooDictionary.Where(x => !x.Value.Boo).ToList();
This will give you all the key value pairs where the MyObject has a Boo value of false.
Note: I changed your line x.Value.Boo == false to !x.Value.Boo as that is the more common syntax and is (IMHO) easier to read/understand the intent.
EDIT
Based on you updating the question to change from dealing with a list to this new ExtensionMethod here is an updated answer (I am leaving the rest as is as it answers what the original posted question was).
// Note this is assuming you can use the new ValueTuples, if not
// then you can change the return to Tuple<string, MyObject>
public static (string key, MyObject myObject) ExtensionMethod(this IEnumerable<KeyValuePair<string, MyObject>> items)
{
// Do whatever it was you were doing here in the original code
// except now you are operating on KeyValuePair objects which give
// you both the object and the key
foreach(var pair in items)
{
if ( YourCondition ) return (pair.Key, pair.Value);
}
}
And use it like this
(string key, MyObject myObject) = fooDictionary.Where(x => !x.Value.Boo).ExtensionMethod();

Dictionary .Values and .Keys to array (in same order)

Is there an elegant way to get a dictionary's keys and values in the same order? I am worried that if I use dict.Values.ToArray() and dict.Keys.ToArray() (or dict.Select(obj => obj.Key) and dict.Select(obj => obj.Value)), that they won't be in the same order.
The simple way to execute this is:
foreach (var keyAndVal in dict)
{
keyList.Add(keyAndVal.Key);
valueList.Add(keyAndVal.Value);
}
var keyArray = keyList.ToArray();
var valueArray = valueList.ToArray();
To me, this feels like the kind of thing that LINQ was made for (but I know that dictionary iteration order is not guaranteed to stay the same in two different calls). Is there an elegant (i.e. LINQ, etc.) way to get these in the same order?
Thanks a lot for your help.
As vcsjones points out, for a standard dictionary, the Keys and Values collections will be in the same order. However, if you want a method that will create key and value arrays that will always be in the same order, for any implementation of IDictionary<TKey, TValue>, you could do something like this:
var keyArray = new TKey[dict.Count];
var valueArray = new TValue[dict.Count];
var i = 0;
foreach (var keyAndVal in dict)
{
keyArray[i] = keyAndVal.Key;
valueArray[i] = keyAndVal.Value;
i++;
}

Remove a single value from a NameValueCollection

My data source could have duplicate keys with values.
typeA : 1
typeB : 2
typeA : 11
I chose to use NameValueCollection as it enables entering duplicate keys.
I want to remove specific key\value pair from the collection, but NameValueCollection.Remove(key) removes all values associated with the specified key.
Is there a way to remove single key\value pair from a NameValueCollection,
OR
Is there a better collection in C# that fits my data
[EDIT 1]
First, thanks for all the answers :)
I think I should have mentioned that my data source is XML.
I used System.Xml.Linq.XDocument to query for type and also it was handy to remove a particular value.
Now, my question is, for large size data, is using XDocument a good choice considering the performance?
If not what are other alternatives (maybe back to NameValueCollection and using one of the techniques mentioned to remove data)
The idea of storing multiple values with the same key is somehow strange. But I think you can retrieve all values using GetValues then remove the one you don't need and put them back using Set and then subsequent Add methods. You can make a separate extension method method for this.
NameValueCollection doesn't really allow to have multiple entries with the same key. It merely concatenates the new values of existing keys into a comma separated list of values (see NameValueCollection.Add.
So there really is just a single value per key. You could conceivably get the value split them on ',' and remove the offending value.
Edit: #ElDog is correct, there is a GetValues method which does this for you so no need to split.
A better option I think would be to use Dictionary<string, IList<int>> or Dictionary<string, ISet<int>> to store the values as discrete erm, values
You may convert it to Hashtable
var x = new NameValueCollection();
x.Add("a", "1");
x.Add("b", "2");
x.Add("a", "1");
var y = x.AllKeys.ToDictionary(k => k, k=>x[k]);
make your own method, it works for me --
public static void Remove<TKey,TValue>(
this List<KeyValuePair<TKey,TValue>> list,
TKey key,
TValue value) {
return list.Remove(new KeyValuePair<TKey,TValue>(key,value));
}
then call it on list as --
list.Remove(key,value); //Pass the key value...
Perhaps not the best way, but....
public class SingleType
{
public string Name;
public int Value;
}
List<SingleType> typeList = new List<SingleType>();
typeList.Add (new SingleType { Name = "TypeA", Value = 1 });
typeList.Add (new SingleType { Name = "TypeA", Value = 3 });
typeList.Remove (typeList.Where (t => t.Name == "TypeA" && t.Value == 1).Single());
You can use the Dictionary collection instead:
Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary.Add("typeA", 1);
dictionary.Add("typeB", 1);
When you try to insert type: 11 it will throw exception as Key already exists. So you can enter a new key to insert this data.
Refer this Tutorial for further help.

c# associative array with dictionary

I want to build an Dictonary like this :
Dictionary<String, ArrayList> myDic = new Dictionary<String, ArrayList>();
in the end i want a structure like :
["blabla"] => array(1,2,3)
["foo"] => array(1,4,6,8)
.......
to build this i run in a loop and in every loop build some strings ,
first question :
how to check every time if this string exists
in the dictionary , if its not exists open a new entry in dictionary with one element in the array list, if exists only add another element to the array list
and another question:
how can i sort this dictionary according to number of elements in the array list(In descending order) like :
["foo"] => array(1,4,6,2,8)
["bar"] => array(4,6,2,8)
["bla"] => array(1,2,3)
["blo"] => array(1,2)
.......
thanks !
Use the right tool for the job. The data structure you want is called a "multi-dictionary" - that is a dictionary that maps from a key to a sequence of values, rather than from a key to a unique value.
The PowerCollections codebase contains an implementation of MultiDictionary that probably does what you want. I would use it rather than writing your own.
To sort the dictionary into a sequence of key/sequence pairs ordered by the length of the sequence, I would use a LINQ query with an "order by" clause. That seems like the easiest way to do it.
Instead of ArrayList you should use an array or List<T>. Assuming you have a Dictionary<string, int> called source this should work:
var items = source
.GroupBy(kvp => kvp.Key)
.Select(grp => new { Key = grp.Key, Items = grp.Select(kvp => kvp.Value).ToArray() })
.OrderByDescending(i => i.Items.Length);
To explain, Dictionary<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>> so can be considered a sequence of key-value pairs. Group by groups the pairs by key and then Select creates a sequence of an anonymous type which contains the key and associated values in a Key and Items property respectively. This sequence is then ordered by the number of items in the Items array of each object.
If you want to order them by the length of the created array, you can't use a dictionary since they are not ordered.
To check if a key exists in a dictionary and use the value if it does, you can use TryGetValue:
ArrayList array;
if(!myDic.TryGetValue("blabla", out array))
{
array = new ArrayList();
myDic["blabla"] = array;
}
array.Add(42);
Would something like this work:
if (myDic.ContainsKey(myString))
myDic[myString].Add(myNumber);
else
myDic.Add(myString, new ArrayList(new int[] {myNumber}));

Sort Hashtable by (possibly non-unique) values

I have a Hashtable that maps strings to ints. Strings are unique, but several may be mapped to the same integer.
My naive approach was to simply invert the Hashtable to a SortedList that is indexed by the Hashtable's values, but the problem is that you get a clash as soon as two of the Hashtable's strings map to the same value.
What is the most efficient way to list my entire Hashtable (keys and values) ordered by the values? (Where two values are the same, I don't care about their ordering.)
Using Linq:
hashtable.Cast<DictionaryEntry>().OrderBy(entry => entry.Value).ToList()
You said you wanted the most efficient method. The following code is the best I could find.
Hashtable hashtable = GetYourHashtable();
var result = new List<DictionaryEntry>(hashtable.Count);
foreach (DictionaryEntry entry in hashtable)
{
result.Add(entry);
}
result.Sort(
(x, y) =>
{
IComparable comparable = x.Value as IComparable;
if (comparable != null)
{
return comparable.CompareTo(y.Value);
}
return 0;
});
foreach (DictionaryEntry entry in result)
{
Console.WriteLine(entry.Key.ToString() + ":" + entry.Value.ToString());
}
I experimented with various different approaches using Linq, but the above method was about 25-50% faster.
Maybe this could work:
myhashtable.Keys.Select(k => new List<string, int>() {k, myhashtable[k]})
.OrderBy(item => item[1]);
This should give you a list of lists, with the nested lists containing exactly two elements, the key and the value. Sorted by the value (second element).
I'm not quite sure if the Hashtable has a KeyValuePair<K, V> type... something like this could also work:
myhashtable.Items.OrderBy(kvp => kvp.Value);
The immediate way that springs to mind is along the lines of what you have except that you have a SortedList (or similar) that uses the original values (ie the integers) as keys and as values has a list of the original keys (ie the strings if I understand correctly). There is a bit more faff involved in adding values (since you need to check if they exist and add them to the list if so or create a new list otherwise). There may be better methods but this is the one that immediately springs to mind...

Categories

Resources