I have declared and populated the following collection.
protected static Dictionary<string, string> _tags;
Now I want to look locate a particular entry in the collection. I tried the following.
thisTag = _tags.FirstOrDefault(t => t.Key == tag);
if (thisTag != default(KeyValuePair<string, string>))
...
And I get the error:
Operator '!=' cannot be applied to operands of type 'System.Collections.Generic.KeyValuePair' and ''
Initially I attempted to compare the result to null, and I guess that's not supported with structs.
I would've thought that finding an item within a collection is a very trivial task. So how the heck to I determine if the item I'm looking for was found?
(Note: I'm using Dictionary because I want fast lookups. I know I can use Contains() to determine if the item is there. But that means a total of two lookups, which sort of defeats the purpose of having a fast lookup. I'll happily using a different collection if it can quickly lookup an item and I have a way to determine if it was successful.)
thisTag = _tags.FirstOrDefault(t => t.Key == tag);
is an inefficient and a little bit strange way to find something by key in a dictionary. Looking things up for a Key is the basic function of a Dictionary.
The basic solution would be:
if (_tags.Containskey(tag)) { string myValue = _tags[tag]; ... }
But that requires 2 lookups.
TryGetValue(key, out value) is more concise and efficient, it only does 1 lookup. And that answers the last part of your question, the best way to do a lookup is:
string myValue;
if (_tags.TryGetValue(tag, out myValue)) { /* use myValue */ }
VS 2017 update, for C# 7 and beyond we can declare the result variable inline:
if (_tags.TryGetValue(tag, out string myValue))
{
// use myValue;
}
// use myValue, still in scope, null if not found
Sometimes you still need to use FirstOrDefault if you have to do different tests.
If the Key component of your dictionnary is nullable, you can do this:
thisTag = _tags.FirstOrDefault(t => t.Key.SubString(1,1) == 'a');
if(thisTag.Key != null) { ... }
Using FirstOrDefault, the returned KeyValuePair's key and value will both be null if no match is found.
It's possible to find the element in Dictionary collection by using ContainsKey or TryGetValue as follows:
class Program
{
protected static Dictionary<string, string> _tags = new Dictionary<string,string>();
static void Main(string[] args)
{
string strValue;
_tags.Add("101", "C#");
_tags.Add("102", "ASP.NET");
if (_tags.ContainsKey("101"))
{
strValue = _tags["101"];
Console.WriteLine(strValue);
}
if (_tags.TryGetValue("101", out strValue))
{
Console.WriteLine(strValue);
}
}
}
Of course, if you want to make sure it's in there otherwise fail then this works:
thisTag = _tags[key];
NOTE: This will fail if the key,value pair does not exists but sometimes that is exactly what you want.
This way you can catch it and do something about the error.
I would only do this if I am certain that the key,value pair is or should be in the dictionary and if not I want it to know about it via the throw.
Related
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();
I have a list of dictionaries
var ProductItemsDictionary = new List<Dictionary<string, string>>();
Is it possible to use linq to search the list and find a dictionary based on a key inside that dictionary and retrieve the value?
Sure it is, but is it worth? See for instance the dotctor's answer. It will do the job, but is inefficient - 2 key lookups (one for checking and one for retrieving the value), compiler generated class and heap allocation (because of the specificKey variable capture), etc. Less code? More readable? What about the non linq equivalent:
static void Foo(List<Dictionary<string, string>> ProductItemsDictionary, string key)
{
string value;
foreach (var dictionary in ProductItemsDictionary)
if (dictionary.TryGetValue(key, out value)) { /* Use value */ }
// Not found
}
Zero allocations, minimum key lookups, good readability (IMO) - what else do we need? :-)
I have a Dictionary property
public Dictionary<string, bool> SearchType { get; set; }
this Dictionary has 4 keys and 4 values for that keys. Now I take them to a variable from SearchType, if the values are true
var searchTypes = searchDetail.SearchType.Where(x => x.Value == true).ToList();
Here I checked the key is CKBinstituteType or CKBstate and etc, from the below code
foreach (var searchType in searchTypes)
{
if (searchType.Key.Contains("CKBinstituteType"))
{
}
if (searchType.Key.Contains("CKBstate"))
{
}
if (searchType.Key.Contains("CKBlocation"))
{
}
if (searchType.Key.Contains("CKBdistance"))
{
}
}
or tried with this way (used equal operation instead of contains)
foreach (var searchType in searchTypes)
{
if (searchType.Key == "CKBinstituteType")
{
}
if (searchType.Key == "CKBstate")
{
}
if (searchType.Key == "CKBlocation")
{
}
if (searchType.Key == "CKBdistance")
{
}
}
What is the difference between of them? Which one is good for my situation? (like performance, code standard,etc)
What is the different between of them?
Both, Contains and Equals are using string comparison. Since your Key is of type string, Contains will check if the passed parameter is part of the key, whereas Equals compares the complete string for equality.
Which one is good for my situation? (like performance, code
standard,etc)
Use ContainsKey method , instead of string equals or contains.
Contains and Equals are used inside the foreach loop, where you are comparing the Key which is a string with Contains and Equals. You don't need to iterate each item in the dictionary. If you are trying to access it through Key, It is about doing a Linear search with complexity of O(n) vs doing dictionary lookup with complexity O(1)
You can use ContainsKey Like
if (SearchType.ContainsKey("CKBinstituteType"))
{
}
Currently you are converting your Dictionary to List, I am not sure if there is really a need your dictionary to a List and then do a linear search. If you really have to filter out the Dictionary based on true values then project the result set into a dictionary and then use ContainsKey like:
var searchTypes = searchDetail.SearchType.Where(r => r.Value == true)
.ToDictionary(r => r.Key, r => r.Value);
if (searchTypes.ContainsKey("CKBinstituteType"))
{
}
if (searchTypes.ContainsKey("CKBstate"))
{
}
if (searchTypes.ContainsKey("CKBlocation"))
{
}
if (searchTypes.ContainsKey("CKBdistance"))
{
}
The difference is that
stringExpr.Contains("CKBinstituteType")
checks if there is some substring of stringExpr which is equal to "CKBinstituteType", while
stringExpr == "CKBinstituteType"
checks if stringExpritself is equal to "CKBinstituteType".
In both cases an ordinal comparison (which is culture invariant) is used. As an explicit example
"xyzxyzCKBinstituteTypexyzxyzxyz".Contains("CKBinstituteType")
is true while
"xyzxyzCKBinstituteTypexyzxyzxyz" == "CKBinstituteType"
is false.
Performance: stringExpr.Contains("CKBinstituteType") will be slower than stringExpr == "CKBinstituteType". Note that I am not addressing the fact that these strings are keys in a Dictionary<string, Something>. See Habib's answer. A Dictionary<,> offers fast (O(1)) lookup on key. You don't utilize that when you do dict.Where(x => criterion).ToList().
contains() checks for a sub string , where as equals() checks for whole string , and other difference is , contains() takes object of CharSequence class where as equals() takes Object as its parameter
Regarding simply whether using Compare or Equals on equivalent strings makes any difference:
Using ReSharper to see the source code for Compare, the first thing it does is
if ((Object)strA == (Object)strB)
{
return 0;
}
So it looks like they would essentially be the same for equivalent strings.
As far as performance, this blog discusses the difference, although the comments include the most useful comparisons. Most commentators seemed to find negligible difference even after running them in very large loops. The last comment though shows a large difference between Equals and Contains and makes me wonder why the results didn't more closely mirror the others.
I have objects in hashtable, in that object I have a list, how to access it?
ls.cs
class lh
{
public string name;
public List<ulong> nList = new List<ulong>();
public lh(string name)
{
this.name = name; ;
}
}
Program.cs
static void Main(string[] args)
{
while((line=ps.ReadLine()) != null)
{
gen.h_lh.Add(line, new lh(line));
}
}
public class gen
{
public static Hashtable h_lh = new Hashtable();
}
this works. when I debug I can see the object created in the hashtable; I just cant/dont know how to access/store value to the list
it's gotta be something like gen.h_lh[lh].something right ? but this didnt work. what did I miss?
First of all Hashtable is obsolete, use Dictionary<TKey, TValue> instead (Dictionary<string, lh> in your case).
Given a key, you can access the value of that key with: h_lh[key].
Or you can enumerate all of the key/value pairs with:
foreach (KeyValuePair<string, lh> pair in h_lh)
pair.Value // this is an lh object
You can also enumerate just keys h_lh.Keys, or just values h_lh.Values.
A hash tables is a data structure that represents a set. That means that by definition, you don't want to access the hash table to get an element, you just want to add, remove, or aks if an element exists. These are the basic operations with sets.
This said, HashSet<T> in .NET has no indexer. Why? Consider the line that you wrote yourself:
var item = gen.h_lh[lh]
If you really can provide the lh to index, what do you expect the hash table to give you? The same instance? Of course not, you already have it, if you are using it in the indexer. So perhaps your problem it's not very well determined.
First of all you need to determine why (and how) you want to access the elements. All you want is to iterate through all of them, or you want to quickly index any one of them? If you just want to get all the elements at some point, then you have all you need: HashSet<T> implements IEnumerable<T>. If you need to get an specific element, then you must have some key to identify the element (like the name property here), and in this case what you want is not a HashSet<lh> but a Dictionary<string,lh>, just like #Tergiver said.
foreach(System.System.Collections.DictionaryEntry entry in h_lh)
{
Console.WriteLine("Key: " + entry.Key.ToString() + " | " + "Value: " + entry.Value.ToString());
}
or you could access it using a key
lh myLh = h_lh[line];
Update answer for comment
foreach(System.System.Collections.DictionaryEntry entry in h_lh)
{
List<ulong> nList = (ulong)entry.Value;
nList.Add(1);
}
I have a Dictionary<int, int> and would like to update certain elements all at once based on their current values, e.g. changing all elements with value 10 to having value 14 or something.
I imagined this would be easy with some LINQ/lambda stuff but it doesn't appear to be as simple as I thought. My current approach is this:
List<KeyValuePair<int, int>> kvps = dictionary.Where(d => d.Value == oldValue).ToList();
foreach (KeyValuePair<int, int> kvp in kvps)
{
dictionary[KeyValuePair.Key] = newValue;
}
The problem is that dictionary is pretty big (hundreds of thousands of elements) and I'm running this code in a loop thousands of times, so it's incredibly slow. There must be a better way...
This might be the wrong data structure. You are attempting to look up dictionary entries based on their values which is the reverse of the usual pattern. Maybe you could store Sets of keys that currently map to certain values. Then you could quickly move these sets around instead of updating each entry separately.
I would consider writing your own collection type to achieve this whereby keys with the same value actually share the same value instance such that changing it in one place changes it for all keys.
Something like the following (obviously, lots of code omitted here - just for illustrative purposes):
public class SharedValueDictionary : IDictionary<int, int>
{
private List<MyValueObject> values;
private Dictionary<int, MyValueObject> keys;
// Now, when you add a new key/value pair, you actually
// look in the values collection to see if that value already
// exists. If it does, you add an entry to keys that points to that existing object
// otherwise you create a new MyValueObject to wrap the value and add entries to
// both collections.
}
This scenario would require multiple versions of Add and Remove to allow for changing all keys with the same value, changing only one key of a set to be a new value, removing all keys with the same value and removing just one key from a value set. It shouldn't be difficult to code for these scenarios as and when needed.
You need to generate a new dictionary:
d = d.ToDictionary(w => w.Key, w => w.Value == 10 ? 14 : w.Value)
I think the thing that everybody must be missing is that it is exceeeeedingly trivial:
List<int> keys = dictionary.Keys.Where(d => d == oldValue);
You are NOT looking up keys by value (as has been offered by others).
Instead, keys.SingleOrDefault() will now by definition return the single key that equals oldValue if it exists in the dictionary. So the whole code should simplify to
if (dictionary.ContainsKey(oldValue))
dictionary[key] = newValue;
That is quick. Now I'm a little concerned that this might indeed not be what the OP intended, but it is what he had written. So if the existing code does what he needs, he will now have a highly performant version of the same :)
After the edit, this seems an immediate improvement:
foreach (var kvp in dictionary.Where(d => d.Value == oldValue))
{
kvp.Value = newValue;
}
I'm pretty sure you can update the kvp directly, as long as the key isn't changed