I have a following hash table:
private Hashtable Sid2Pid = new Hashtable();
Sid2Pid.Add(1,10);
Sid2Pid.Add(2,20);
Sid2Pid.Add(3,20);
Sid2Pid.Add(4,30);
Now how to get the list of keys from the above hashtable that has a value of 20 using LinQ
Use a Dictionary<int, int> instead of a Hashtable (see here for why) then do the following:
var keys = Sid2Pid.Where(kvp => kvp.Value == 20)
.Select(kvp => kvp.Key);
A HashTable is IEnumerable of DictionaryEntry, with a little casting this can be converted into something the LINQ operators can work on:
var res = from kv in myHash.Cast<DictionaryEntry>
where (int)kv.Value = targetValue
select (int)kv.Key;
NB. This will throw an exception if you pass different types.
Related
I have this
foreach (KeyValuePair<string, Object> tempData in tempList.ToDictionary(x => x.Key, y => y.Value))
{
tempData["fahrzeugA"] = "s";
}
But using tempData["fahrzeugA"] = "s"; will not work.
I get:
Cannot apply indexing with [] to an expression of type
'System.Collections.Generic.KeyValuePair'
What is the correct syntax if I have an existing key fahrzeugA, which I want to alter ?
You can apply this :
var tempList = new List<Test>();
var dic = tempList.ToDictionary(x => x.Key, y => y.Value);
foreach (var tempData in dic)
{
dic[tempData.Key] = "s";
}
You can't change the key value pair since it is an immutable struct. The only way to change it is to create a new instance. That instance would live independent from the dictionary.
If you want to change the value in the dictionary, use the indexer property on the dictionary to change the value.
And even then, the dictionary will go out of scope immediately, so there is no use setting it. It won't affect the original list.
Check KeyValuePair.Value Property. It's readonly and can't be altered.
ToDictionary creates a new object. You can't alter original object by accessing its elements' value.
You have to remove this specific item from original list and add new item of the same key back.
var removeIndex = tempList.FindIndex(kp => kp.Key == "fahrzeugA");
tempList.RemoveAt(removeIndex);
tempList.Add(new KeyValuePair<string, string>("fahrzeugA", "s"));
If there are multiple "fahrzeugA" items (it's valid in list but not valid in dictionary), use RemoveAll instead.
If your tempList is List<KeyValuePair<string, Object>> type:
for (var i = 0; i < tempList.Count; ++i) {
if (tempList[i].Key == "fahrzeugA") {
tempList[i] = new KeyValuePair<string, object> ("fahrzeugA", "s"); // KeyValuePair<string, object> might be changed with your own type if you use something else.
break; // If you want to modify only first KeyValuePair.
}
}
If you have successfully turned your tempList into a dictionary, there can only be one "fahrzeugA" (since all keys must be unique), so looping makes no sense.
You should be able to just say:
var dictionary = tempList.ToDictionary(x => x.Key, y => y.Value);
dictionary["fahrzeugA"] = "s";
If you don't want to create the dictionary in the first place, you could do this:
var matchingKeyValuePair = tempList.SingleOrDefault(x => x.Key == "fahrzeugA");
if (matchingKeyValuePair != null) matchingKeyValuePair.Value = "s";
If you are using a list of .NET KeyValuePair<TKey, TValue>, which is an immutable struct, you can replace the value with a new KeyValuePair, like this:
var matchingIndex = tempList.FindIndex(x => x.Key == "fahrzeugA");
if (matchingIndex >= 0)
tempList[matchingIndex] = new KeyValuePair<string, string>("fahrzeugA", "s");
Note, this assumes that you only have one item with a key of "fahrzeugA".
I have a list of KeyValuePair which its values are list too such as
List<KeyValuePair<string, List<string>>> ListX = new List<KeyValuePair<string,List<string>>>();
ListX.Add(new KeyValuePair<string,List<string>>("a",list1));
ListX.Add(new KeyValuePair<string,List<string>>("b",list1));
ListX.Add(new KeyValuePair<string,List<string>>("a",list1));`
I want the keys of each KeyValuePair in the list to be not duplicated, only the keys, can I use Distinct in this list?
for example I want the third item in the list that has "a" key to be deleted because it's duplicated.
Though it is possible to work around with your current List to make it having Distinct keys, the simplest solution which I think fit for your case is to use Dictionary<string,List<string>>
It does just exactly what you need:
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
dict.Add("a", new List<string>());
dict.Add("b", new List<string>());
dict.Add("a", new List<string>()); //will throw an error
Image:
If you need to check if a Key is already exist when you want to add a <Key,Value> to a your dictionary, simply check by ContainsKey:
if (dict.ContainsKey(key)) //the key exists
var dictionaryX = ListX
.GroupBy(x => x.Key, (x, ys) => ys.First())
.ToDictionary(x => x.Key, x => x.Value);
I'm not sure if this is what you were looking for, but it's a query that will convert a ListX into a dictionary by only taking the first value for each duplicate key.
You can use class Dictionary<TKey, TValue> which inherits from IEnumerable<KeyValuePair<TKey, TValue>>. It is a collection of KeyValuePairs which allows only unique keys.
U can use
Dictionary<TKey, TValue>
where Tkey and Tvalue are generic datatypes.
For example they can be int, string,another dictionary etc.
ExampleDictionary<int , string>, Dictionary<int , List<employee>> etc.
In all these cases the key is the distinct part ie, same key cannot be inserted again.
U can check if key exists using Distinct so that no exception occurs even if u try to add same key
However Distinct prevents only same key value pairs .
To prevent same key being added use Enumerable.GroupBy
ListItems.Select(item =>
{
long value;
bool parseSuccess = long.TryParse(item.Key, out value);
return new { Key = value, parseSuccess, item.Value };
})
.Where(parsed => parsed.parseSuccess)
.GroupBy(o => o.Key)
.ToDictionary(e => e.Key, e => e.First().Value)
List<Dictionary<int, List<int>>> list = new List<Dictionary<int, List<int>>>(); //List with a dictinary that contains a list
int key = Convert.ToInt32(Console.ReadLine()); // Key that you want to check if it exist in the dictinary
int temp_counter = 0;
foreach(Dictionary<Int32,List<int>> dict in list)
{
if(dict.ContainsKey(key))
temp_counter+=temp_counter;
}
if (temp_counter == 0) // key not present in dictinary then add a to the list a dictinary object that contains your list
{
Dictionary<int,List<int>> a = new Dictionary<int,List<int>>();
a.Add(key,new List<int>()); // will contain your list
list.Add(a);
}
Check if this works
I have my Lookup looking like this:
Lookup<string, DataModel> lookup;
Besides that I have dictionary containing key mappings:
Dictionary<string, KeyModel> keyMappings;
What I want to do is to re-map string keys in lookup to the KeyModel entities in the following way:
Lookup <string, DataModel> lookup;
||
||
Dictionary<string, KeyModel> keyMappings;
___________|
v
Lookup<KeyModel, DataModel> result;
Given:
Dictionary<string, KeyModel> keyMappings = ...;
ILookup<string, DataModel> lookup = ...;
the response is:
ILookup<KeyModel, DataModel> lookup2 = lookup
.SelectMany(x => x, (grouping, element) => new { Key = keyMappings[grouping.Key], Element = element })
.ToLookup(x => x.Key, x => x.Element);
So you first re-linearize the ILookup<,> by using SelectMany, and then recreate the ILookup<,>.
Clearly you need your KeyModel to define the GetHashCode() and the Equals(), or you need an IEqualityComparer<KeyModel> to pass as the parameter of the ToLookup()
You can use a simple foreach-loop.
First you need to transform your Lookup into a Dictionary. See here.
foreach (KeyValuePair<string, DataModel> kvp in lookup) {
KeyModel outValue;
if (keyMappings.TryGetValue(kvp.Key, out outValue))
{
result.Add(outValue, lookup[kvp.Key]);
}}
Not the fastest solution, maybe someone is coming up with a nice LINQ.
I am trying to query a list of dictionary by dictionary key and value using linq. The following gives me the error of "cannot convert keyvaluepair to type bool."
Thanks in advance.
var list = new List<Dictionary<string, object>>();
foreach (DataRow row in wordCloud.Rows)
{
var dict = new Dictionary<string, object>();
foreach (DataColumn col in wordCloud.Columns)
{
dict[col.ColumnName] = row[col];
}
list.Add(dict);
}
if (!string.IsNullOrWhiteSpace(text))
{
var item = list.Where(dict => dict.Where(x => x.Key == "word" && x.Value == text)).FirstOrDefault();
}
Thanks this is what I am using.
var item = list.Where(dict => dict["WORD"].Equals(text)).FirstOrDefault();
Your compiler error is caused by your predicate in list.Where not using a Boolean expression. dict.Where(...) is going to produce an IEnumerable<KeyValuePair<K,V>>, which is not a Boolean operation. Furthermore, your technique misuses a dictionary, because it will only have one pair that has a given key, there is no need to loop over it. To deal with both issues, I suggest writing a method to investigate the dictionary and produce a Boolean result for matches.
bool DictionaryContainsText(Dictionary<string, object> dictionary, string text)
{
string key = "word";
if (dictionary.ContainsKey(key) && dictionary[key] != null)
{
return dictionary[key].Equals(text);
}
return false;
}
You can then consume this method in the filtering of your list.
var item = list.Where(dict => DictionaryContainsText(dict, text)).FirstOrDefault();
All that said, I wonder if you are starting from the wrong design? A DataTable to a List<Dictionary<K,V>> seems a bit less intuitive to use than a list of a defined type. Should you not consider defining a class with appropriately named (and typed!) properties that you could consume instead? This is left as an activity for you to consider.
Your error is happening because the predicate of list.Where( ... ) is dict => dict.Where( ... ) which isn't a Boolean value.
Depending on how you want your code to work, you could potentially replace it with list.FirstOrDefault(dict => dict.Any( ... )), which would eventually return the first dictionary that contains the key-value pair ("word", text). (I think this is the intended functionality of the code, but I can't be positive without further information.)
Is there a built-in function for converting a string array into a dictionary of strings or do you need to do a loop here?
Assuming you're using .NET 3.5, you can turn any sequence (i.e. IEnumerable<T>) into a dictionary:
var dictionary = sequence.ToDictionary(item => item.Key,
item => item.Value)
where Key and Value are the appropriate properties you want to act as the key and value. You can specify just one projection which is used for the key, if the item itself is the value you want.
So for example, if you wanted to map the upper case version of each string to the original, you could use:
var dictionary = strings.ToDictionary(x => x.ToUpper());
In your case, what do you want the keys and values to be?
If you actually just want a set (which you can check to see if it contains a particular string, for example), you can use:
var words = new HashSet<string>(listOfStrings);
You can use LINQ to do this, but the question that Andrew asks should be answered first (what are your keys and values):
using System.Linq;
string[] myArray = new[] { "A", "B", "C" };
myArray.ToDictionary(key => key, value => value);
The result is a dictionary like this:
A -> A
B -> B
C -> C
IMO, When we say an Array we are talking about a list of values that we can get a value with calling its index (value => array[index]), So a correct dictionary is a dictionary with a key of index.
And with thanks to #John Skeet, the proper way to achieve that is:
var dictionary = array
.Select((v, i) => new {Key = i, Value = v})
.ToDictionary(o => o.Key, o => o.Value);
Another way is to use an extension method like this:
public static Dictionary<int, T> ToDictionary<T>(this IEnumerable<T> array)
{
return array
.Select((v, i) => new {Key = i, Value = v})
.ToDictionary(o => o.Key, o => o.Value);
}
If you need a dictionary without values, you might need a HashSet:
var hashset = new HashSet<string>(stringsArray);
What do you mean?
A dictionary is a hash, where keys map to values.
What are your keys and what are your values?
foreach(var entry in myStringArray)
myDictionary.Add(????, entry);
I'll assume that the question has to do with arrays where the keys and values alternate. I ran into this problem when trying to convert redis protocol to a dictionary.
private Dictionary<T, T> ListToDictionary<T>(IEnumerable<T> a)
{
var keys = a.Where((s, i) => i % 2 == 0);
var values = a.Where((s, i) => i % 2 == 1);
return keys
.Zip(values, (k, v) => new KeyValuePair<T, T>(k, v))
.ToDictionary(kv => kv.Key, kv => kv.Value);
}
Dictionary<int, string> dictionaryTest = new Dictionary<int, string>();
for (int i = 0; i < testArray.Length; i++)
{
dictionaryTest.Add(i, testArray[i]);
}
foreach (KeyValuePair<int, string> item in dictionaryTest)
{
Console.WriteLine("Array Position {0} and Position Value {1}",item.Key,item.Value.ToString());
}
The Question is not very clear, but Yes you can convert a string to Dictionary provided the string is delimited with some characters to support Dictionary<Key,Value> pair
So if a string is like a=first;b=second;c=third;d=fourth you can split it first based on ; then on = to create a Dictionary<string,string> the below extension method does the same
public static Dictionary<string, string> ToDictionary(this string stringData, char propertyDelimiter = ';', char keyValueDelimiter = '=')
{
Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
Array.ForEach<string>(stringData.Split(propertyDelimiter), s =>
{
if(s != null && s.Length != 0)
keyValuePairs.Add(s.Split(keyValueDelimiter)[0], s.Split(keyValueDelimiter)[1]);
});
return keyValuePairs;
}
and can use it like
var myDictionary = "a=first;b=second;c=third;d=fourth".ToDictionary();
since the default parameter is ; & = for the extension method.
You can create a dictionary from an IEnumerable<T>, including an array, via:
var dictionary = myEnumerable.ToDictionary(element => element.Key,
element => element.Value)
where Key and Value are the key and value you want to store in each dictionary element. Available in .NET Framework 3.5+/.NET Core 1.0+/.NET 5.0+. Official documentation.
If you want the dictionary values to be the elements from the original enumerable:
var dictionary = myEnumerable.ToDictionary(element => element.Key)
If you only need high-performance set operations, you may be able to use:
var words = new HashSet<string>(listOfStrings);
In simple terms, the HashSet class can be thought of as a Dictionary<TKey,TValue> collection without values. Official documentation.
(Note that a 'sequence' in an entirely unrelated object.
Originally submitted an existing answer edit but it was rejected by the author so posting separately, including with links to the official Microsoft documentation.)