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.
Related
Given that I have a collection of objects and a collection of key=value pairs, how would I construct a lambda (or, if lambda is inappropriate, another expression) so that it filters the original collection based on the settings of the second.
Example: a collection of missions and given a map contains type=flight and location=USA, return all flight missions in the USA.
This question is in conjunction with another question, but as they are separate things I made two questions out of it.
Assume I have something like:
Dictionary<string, string> filters; //type and location are keys, flight and USA are the values, respectively
List<Mission> missions;
Existing currently we have something like:
var badIds;
return missions.Where(x => !badIds.contains(x.ids)))
.Select(x => x.ids);
The thing is, in this case I have to know at compile time that I want to filter based on ids and use a single dimension array like collection to do it. I want to use two dimensions and include not only what values I'm looking for, but what parameter to look in for it while also dynamically expanding the number of filter operations based on the number of parameters. They may specify one, the other, both, more parameters, less, in any combination, etc (0 parameters may be a special case, but that's easy enough).
I want something like:
for ( KeyValuePair kvp in filters )
{
missions = missions.Where(x => x.(kvp.Key) == kvp.Value);
}
//I'm new to lambdas and C# so this is probably terrible.
From your description, this is what I gather you are trying to do:
IEnumerable<Mission> FindMissions(IEnumerable<Mission> missions, string flight, string location)
{
var results = new List<Mission>();
foreach (Mission m in missions)
{
if (m.Type == flight && m.Location == location)
{
results.Add(m);
}
}
return results;
}
I'm posting my own solution to this so it can be judged. Let me know what you guys think.
for ( KeyValuePair kvp in filters )
{
missions = missions.Where(x => x.GetType().GetProperty(kvp.Key).GetValue(x, null) == kvp.Value;
}
I've never done reflection before so the performance implications are unknown.
I have a getvalue object that contains a price list which consists of 5 items. I need to get the value of one of the elements. I can get the value by index:
return (getValue1.ValuationPrices[4].Value.ToString());
Instead of using 4 (the index) I would like to use the name of the field. Can I do that?
More detail:
I want to say if PriceType is "Wholesale" return the value that is 18289
that is the answer to this question:
foreach (var item in getValue1.ValuationPrices)
{
if (item.PriceType == ServiceReference1.PriceType.Wholesale)
{
carValue= item.Value.ToString();
}
}
You can either change your array to Dictionary<string, yourType> or use LINQ to perform linear search for your object by name:
return getValue1.ValuationPrices.First(x => x.Name == "myName").Value.ToString();
You could do this by adding an indexer property to the ValuationPrices type.
public ValuationPrice this[string name]
{
get
{
return this.First(n => n.Name == value);
}
}
Then you would be able to write getvalue1.ValuationPrices["fieldName"].
The implementation of the indexer property will vary depending on the internal structure of your classes, but hopefully this gives you some idea of the syntax used to implement the indexer.
The screenshot helped quite a bit... people can't guess what your classes look like internally. Your comment to Marcin indicates that PriceType might be an enumeration. So assuming:
PriceType is actually an enum, not a string
The PriceType you're searching for is guaranteed to be in that collection at once and one time only
This should work:
return getValue1.ValuationProces.Single(x => x.PriceType == PriceType.WholeSale).Value.ToString();
This is basically the same as Marcin's - if I'm right about PriceType being an enum and this works, then you should just accept his answer and move on.
Currently I am using a Dictionary<int,node> to store around 10,000 nodes. The key is used as an ID number for later look up and the 'node' is a class that contains some data. Other classes within the program use the ID number as a pointer to the node. (this may sound inefficient. However, explaining my reasoning for using a dictionary for this is beyond the scope of my question.)
However, 20% of the nodes are duplicate.
What i want to do is when i add a node check to see if it all ready exists. if it does then use that ID number. If not create a new one.
This is my current solution to the problem:
public class nodeDictionary
{
Dictionary<int, node> dict = new Dictionary<int, node>( );
public int addNewNode( latLng ll )
{
node n = new node( ll );
if ( dict.ContainsValue( n ) )
{
foreach ( KeyValuePair<int, node> kv in dict )
{
if ( kv.Value == n )
{
return kv.Key;
}
}
}
else
{
if ( dict.Count != 0 )
{
dict.Add( dict.Last( ).Key + 1, n );
return dict.Last( ).Key + 1;
}
else
{
dict.Add( 0, n );
return 0;
}
}
throw new Exception( );
}//end add new node
}
The problem with this is when trying to add a new node to a list of 100,000 nodes it takes 78 milliseconds to add the node. This is unacceptable because i could be adding an additional 1,000 nodes at any given time.
So, is there a better way do do this? I am not looking for someone to write the code for me, I am just looking for guidance.
It sounds like you want to
make sure that LatLng overrides Equals/GetHashCode (preferrably implement the IEquatable<LatLng> interface)
stuff all the items directly into a HashSet<LatLng>
For implementing GetHashCode, see here: Why is it important to override GetHashCode when Equals method is overridden?
If you need to generate 'artificial' unique IDs in some fashion, I suggest you use the dictionary approach again, but 'in reverse':
// uses the same hash function for speedy lookup/insertion
IDictionary<LatLng, int> idMap = new Dictionary<LatLng, int>();
foreach (LatLng latLng in LatLngCoords)
{
if (!idMap.ContainsKey(latLng))
idMap.Add(latLng, idMap.Count+1); // to start with 1
}
You can have the idMap replace the HashSet<>; the implementation (and performance characteristics) is essentially the same but as an associative container.
Here's a lookup function to get from LatLng to Id:
int IdLookup(LatLng latLng)
{
int id;
if (idMap.TryGetValue(latLng, id))
return id;
throw new InvalidArgumentException("Coordinate not in idMap");
}
You could just-in-time add it:
int IdFor(LatLng latLng)
{
int id;
if (idMap.TryGetValue(latLng, id))
return id;
id = idMap.Count+1;
idMap.Add(latLng, id);
return id;
}
I'd add a second dictionary for the reverse direction. i.e. Dictionary<Node,int>
Then you either
Are content with reference equality and do nothing.
Create an IEqualityComparer<Node> and supply it to the dictionary
Override Equals and GetHashCode on Node
In both cases a good implementation for the hashcode is essential to get good performance.
Your solution is not only slow, but also wrong. The order of items in a Dictionary is undefined, so dict.Last() is not guaranteed to return the item that was added last. (Although it may often look that way.)
Using an id to identify an object in your application seems wrong too. You should consider using references to the object directly.
But if you want to use your current design and assuming that you compare nodes based on their latLng, you could create two dictionaries: the one you already have and a second one, Dictionary<latLng, int>, that can be used to efficiently fond out whether a certain node already exists. And if it does, it gives you its id.
What exactly is the purpose of this code?
if ( dict.ContainsValue( n ) )
{
foreach ( KeyValuePair kv in dict )
{
if ( kv.Value == n )
{
return kv.Key;
}
}
}
The ContainsValue searches for a value (instead of a key) and is very inefficient (O(n)). Ditto for foreach. Let alone you do both when only one is necessary (you could completely remove ContainsValue by rearranging your ifs a little)!
You should probably mainntain additional dictionary that is "reverse" of the original one (i.e. values in old dictionary are keys in the new one and vice versa), to "cover" your search patterns (similarly to how databases can maintain multiple indexes par table to cover multiple ways table can be queried).
You could try using HashSet<T>
You might want to consider restructuring this to just use a List (where the 'key' is just the index into the List) instead of a Dictionary. A few advantages:
Looking up an element by integer key is now O(1) (and a very fast O(1) given that it's just an array dereference internally).
When you insert a new element, you perform an O(n) search to see whether it already exists in the list. If it does not, you've also already traversed the list and can have recorded whether you encountered an entry with a null record. If you have, that index is the new key. If not, the new key is the current list Count. You're enumerating the collection once instead of multiple times and the enumeration itself is much faster than enumerating a Dictionary.
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.
I have two lists A and B, at the beginning of my program, they are both filled with information from a database (List A = List B). My program runs, List A is used and modified, List B is left alone. After a while I reload List B with new information from the database, and then do a check with that against List A.
foreach (CPlayer player in ListA)
if (ListB.Contains(player))
-----
Firstly, the object player is created from a class, its main identifier is player.Name.
If the Name is the same, but the other variables are different, would the .Contains still return true?
Class CPlayer(
public CPlayer (string name)
_Name = name
At the ---- I need to use the item from ListB that causes the .Contains to return true, how do I do that?
The default behaviour of List.Contains is that it uses the default equality comparer. If your items are reference types this means that it will use an identity comparison unless your class provides another implementation via Equals.
If you are using .NET 3.5 then you can change your second line to this which will do what you want:
if (ListB.Any(x => x.Name == player.Name))
For .NET 2.0 you could implement Equals and GetHashCode for your class, but this might give undesirable behaviour in other situations where you don't want two player objects to compare equal if they have the same name but differ in other fields.
An alternative way is to adapt Jon Skeet's answer for .NET 2.0. Create a Dictionary<string, object> and fill it with the names of all players in listB. Then to test if a player with a certain name is in listB you can use dict.ContainsKey(name).
An alternative to Mark's suggestion is to build a set of names and use that:
HashSet<string> namesB = new HashSet<string>(ListB.Select(x => x.Name));
foreach (CPlayer player in ListA)
{
if (namesB.Contains(player.Name))
{
...
}
}
Assuming you are using the System.Collections.Generic.List class, if the CPlayer class does not implement IEquatable<T> it will use the Equals and GetHashCode functions of the CPlayer class to check if the List has a member that equals the argument of Contains. Assuming that implementation is OK for you, you could something like
CPlayer listBItem = ListB.First(p => p == player);
to get the instance from ListB
It sounds like this is what you need to accomplish:
For each player in list A, find each player in list B with the same name and bring both players into the same scope.
Here is an approach which joins the two lists in a query:
var playerPairs =
from playerA in ListA
join playerB in ListB on playerA.Name equals playerB.Name
select new { playerA, playerB };
foreach(var playerPair in playerPairs)
{
Console.Write(playerPair.playerA.Name);
Console.Write(" -> ");
Console.WriteLine(playerPair.playerB.Name);
}
If you want the .Contains method to match only on CPlayer.Name, then in the CPlayer class implement these methods:
public override bool Equals(object obj)
{
if (!(obj is CPlayer)
return false;
return Name == (obj as CPlayer).Name;
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
If you want the Name comparison to be Case Insensitive, replace use this Equals method instead:
public override bool Equals(object obj)
{
if (!(obj is CPlayer)
return false;
return Name.Equals((obj as CPlayer).Name, StringComparison.OrdinalIgnoreCase);
}
If you do this, your .Contains call will work just as you want it.
Secondly, if you want to select this item in the list, do this:
var playerB = ListB[ListB.IndexOf(player)];
It uses the same .Equals and .GetHashCode methods.
UPD:
This is probably a subjective statement, but you could also squeeze some performance out of it, if your .Equals method compared the Int hashes before doing the string comparison..
Looking at the .NET sources (Reflector FTW) I can see that seemingly only the HastTable class uses GetHashCode to improve it's performance, instead of using .Equals to compare objects every single time. In the case of a small class like this, the equality comparer is simple, a single string comparison.. If you were comparing all properties though, then comparing two integers would be much faster (esp if they were cached :) )
The List.Contains and List.IndexOf don't use the hash code, and use the .Equals method, hence I proposed checking the hash code inside. It probably won't be anything noticeable, but when you're itching to get every single ms of execution (not always a good thing, bug hey! :P ) this might help someone. just saying... :)