C# LINQ Any() Comparig two Lists - linq

I have two lists
List<string> setA = new List<string>() {"cat", "dog", "elephant"};
List<string> setB = new List<string>() {"cat"};
I have bool
bool compare = setA.Any(x => x.Equals(setB.Select(y => y))); which suppose to check for me if any string from setA eqauls string 'cat' from setB. it suppose to be 'true' but it isnt :/ (showing me as 'false')
What Im doing wrong?

Your approach is wrong:
bool compare = setA.Any(x => x.Equals(setB.Select(y => y)));
This does following: checking if any strings in setA equal the IEnumerable<string> instance returned from setB.Select(y => y). So you are basically comparing a string with a LINQ query which is never true.
This is the most efficient way to check if any string in A is in B:
bool compare = setA.Intersect(setB).Any();
You can also use this, which is less efficient if the lists are large;
bool compare = setA.Any(setB.Contains);

Related

LINQ: Improving performance of "query to find all dictionaries from list of dictionaries where given key has at least one value from list of values"

I tried searching for existing questions, but I could not find anything, so apologize if this is duplicate question.
I have following piece of code. This code runs in a loop for different values of key and listOfValues (listOfDict does not change and built only once, key and listOfValues vary for each iteration). This code currently works, but profiler shows that 50% of the execution time is spent in this LINQ query. Can I improve performance - using different LINQ construct perhaps?
// List of dictionary that allows multiple values against one key.
List<Dictionary<string, List<string>>> listOfDict = BuildListOfDict();
// Following code & LINQ query runs in a loop.
List<string> listOfValues = BuildListOfValues();
string key = GetKey();
// LINQ query to find all dictionaries from listOfDict
// where given key has at least one value from listOfValues.
List<Dictionary<string, List<string>>> result = listOfDict
.Where(dict => dict[key]
.Any(lhs => listOfValues.Any(rhs => lhs == rhs)))
.ToList();
Using HashSet will perform significantly better. You can create a HashSet<string> like so:
IEnumerable<string> strings = ...;
var hashSet = new HashSet<string>(strings);
I assume you can change your methods to return HashSets and make them run like this:
List<Dictionary<string, HashSet<string>>> listOfDict = BuildListOfDict();
HashSet<string> listOfValues = BuildListOfValues();
string key = GetKey();
List<Dictionary<string, HashSet<string>>> result = listOfDict
.Where(dict => listOfValues.Overlaps(dict[key]))
.ToList();
Here HashSet's instance method Overlaps is used. HashSet is optimized for set operations like this. In a test using one dictionary of 200 elements this runs in 3% of the time compared to your method.
UPDATED: Per #GertArnold, switched from Any/Contains to HashSet.Overlaps for slight performance improvement.
Depending on whether listOfValues or the average value for a key is longer, you can either convert listOfValues to a HashSet<string> or build your list of dictionaries to have a HashSet<string> for each value:
// optimize testing against listOfValues
var valHS = listOfValues.ToHashSet();
var result2 = listOfDict.Where(dict => valHS.Overlaps(dict[key]))
.ToList();
// change structure to optimize query
var listOfDict2 = listOfDict.Select(dict => dict.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToHashSet())).ToList();
var result3 = listOfDict2.Where(dict => dict[key].Overlaps(listOfValues))
.ToList();
Note: if the query is repeated with differing listOfValues, it probably makes more sense to build the HashSet in the dictionaries once, rather than computing a HashSet from each listOfValues.
#LasseVågsætherKarlsen suggestion in comments to invert the structure intrigued me, so with a further refinement to handle the multiple keys, I created an index structure and tested lookups. With my Test Harness, this is about twice as fast as using a HashSet for one of the List<string>s and four times faster than the original method:
var listOfKeys = listOfDict.First().Select(d => d.Key);
var lookup = listOfKeys.ToDictionary(k => k, k => listOfDict.SelectMany(d => d[k].Select(v => (v, d))).ToLookup(vd => vd.v, vd => vd.d));
Now to filter for a particular key and list of values:
var result4 = listOfValues.SelectMany(v => lookup[key][v]).Distinct().ToList();

Linq Query Filter from two lists where row differs

Not sure how to formulate this Linq query.
I have two lists, each of which contains HashCheck objects:
class HashCheck
{
public string Id {get; set;}
public string Hash {get; set;}
}
So, given
List<HashCheck> list1;
List<HashCheck> list2;
I need a query that will result in a list having rows where the Ids of the rows matches, but the Hash does not.
So for example
List1 =
{1, 12345,
2, 34323,
3, 34083,
4, 09887}
List2 =
{1, 00001, << matching id, not matching hash
2, 34323,
3, 11112, << matching id, not matching hash
4, 09887
5, 98845}
ResultList =
{1, 00001,
3, 11112}
NOTE: in List2, there is an extra row, it would be a bonus if this were included in the ResultList. But I know how to do that in a separate query if necessary.
Thanks for any help.
try this code:
var list3 = (from i in list1
from j in list2
where i.Id == j.Id && i.Hash != j.Hash
select new HashCheck() { Id = j.Id, Hash = j.Hash
}).ToList<HashCheck>();
You can use join. something like below code:
var list3 = (from i in list1
join j in list2 on i.Id equals j.Id
where i.Hash != j.Hash
select new HashCheck() { Id = j.Id, Hash = j.Hash
}).ToList<HashCheck>();
It looks like you want your result to contain the HashCheck objects from list2, which would simply mean:
var ans = list2.Where(hc2 => !list1.Any(hc1 => hc1.Id == hc2.Id && hc1.Hash == hc2.Hash));
e.g. return all list2 elements without a list1 element that matches in both Id and Hash.
If list1 (and/or list2) is very large and performance is a consideration, you can convert list1 to a Dictionary and do lookups against that:
var list1map = list1.ToDictionary(hc1 => hc1.Id, hc1 => hc1.Hash);
var ans2 = list2.Where(hc2 => !list1map.TryGetValue(hc2.Id, out var hash1) || hash1 != hc2.Hash);
Another alternative would be to implement Equals/GetHashCode for your class and then you can use LINQ Except.
Add the following methods to your class:
public override bool Equals(object other) => (other is HashCheck hco) ? Id == hco.Id && Hash == hco.Hash : false;
public override int GetHashCode() => (Id, Hash).GetHashCode();
Now the computation is simple:
var ans3 = list2.Except(list1);
NOTE: Implementing Equals/GetHashCode in this way can be problematic if your HashCode objects are not treated as immutable. Some collection classes really won't like it if the hash code of an object already stored in them changes.
Also, it would be best practice to implement operator== and operator!= as well and possibly IEquatable.

How to sort a list of strings by using the order of the items in another list?

I want to sort a list of strings (with possibly duplicate entries) by using as ordering reference the order of the entries in another list. So, the following list is the list I want to sort
List<String> list = ['apple','pear','apple','x','x','orange','x','pear'];
And the list that specifies the order is
List<String> order = ['orange','apple','x','pear'];
And the output should be
List<String> result = ['orange','apple','apple','x','x','x','pear','pear'];
Is there a clean way of doing this?
I don't understand if I can use list's sort and compare with the following problem. I tried using map, iterable, intersection, etc.
There might be a more efficient way but at least you get the desired result:
main() {
List<String> list = ['apple','pear','apple','x','x','orange','x','pear'];
List<String> order = ['orange','apple','x','pear'];
list.sort((a, b) => order.indexOf(a).compareTo(order.indexOf(b)));
print(list);
}
Try it on DartPad
The closure passed to list.sort(...) is a custom comparer which instead of comparing the passed item, compares their position in order and returns the result.
Using a map for better lookup performance:
main() {
List<String> list = ['apple','pear','apple','x','x','orange','x','pear'];
List<String> orderList = ['orange','apple','x','pear'];
Map<String,int> order = new Map.fromIterable(
orderList, key: (key) => key, value: (key) => orderList.indexOf(key));
list.sort((a, b) => order[a].compareTo(order[b]));
print(list);
}
Try it on DartPad

How to create programmatically single LINQ query w/ OR between Where() clauses (.Where(fn) OR .Where(fn) OR .Where(fn)) programatically

I'd like to know it is it possible to create programmatically single LINQ query (for EntityFramework 6) with N .Where() clauses, but with OR between these .Where() clauses.
Imagine IQueryable object defined like:
var query = dbContext.MyTable.Where(mt => mt.TimeStamp >= DateBegin);
What I need else is add N (unknown number) of Where clauses, but with OR condition between them.
Image list of some object:
List<MyObject> myObj =
new List<MyObject>({new MyObject {val = "a" }, new MyObject { val = "b"}}); //In real code there is more than 1 property.
then I'd like to add Where() clauses to query like:
myObj.ForEach(mo =>{
// THIS CREATES -AND- BETWEEN WHERE CLAUSES, BUT I NEED -OR-
query.Where(q=>q.MyValue == mo.val); // In real code there is more than 1 property to compare
});
I was thinking about .Union() beteween queries, but It could generate union between separated queries and it's not optimal I think.
Thanks!
Here's the solution: linq-to-entities-combining-predicates
Or course is necessary to use "latest" answer:
Copy/Paste class ParameterRebinder
Copy/Paste static class Utility
Usage:
Expression<Func<Car, bool>> theCarIsRed = c => c.Color == "Red";
Expression<Func<Car, bool>> theCarIsCheap = c => c.Price < 10.0;
Expression<Func<Car, bool>> theCarIsRedOrCheap = theCarIsRed.Or(theCarIsCheap);
var query = carQuery.Where(theCarIsRedOrCheap);
Because in my solution is N of expressions, I take first expression and then append other expressions in ForEach cycle.
var firstExpression = expressionList.First();
expressionList.Skip(1).ToList().ForEach(ex => { firstExpression = firstExpression.Or(ex); });

Linq : How do I test a List<bool> for condition where any one of its values == true?

I have a list,
List<bool> MyList;
MyList.Add(true);
MyList.Add(false);
MyList.Add(false);
What is a clean way to use linq to test if any value is true? I tried
MyList.Find(SomeBoolean=>SomeBoolean)
but the result is weird.
Try :
bool test = MyList.Any(x => x);
But you have to initialize your list before inserting anything.
Use Any
var anyTrue = MyList.Any(i => i);
If you want to List all the true value
List<bool> MyList = new List<bool>();
MyList.Add(true);
MyList.Add(false);
MyList.Add(false);
var listTrue = MyList.Where(c => c);
I wonder, what is your actual Class because if you want to .Find is the same result.
var b = MyList.Find(c => c)
maybe you forgot to declare the var or DataType?
myList is a list of bool
myList= getSelectedChannels();
List allTrue= myList.FindAll(a => a == true);
allTrue will be a list of bool that match the criteria (bool is true). Now just say allTrue.Count to get the number of items in that list.

Resources