What am I missing in this chain of predicates? - c#

NOTE: Right before posting this question it occurred to me there's a better way of doing what I was trying to accomplish (and I feel pretty stupid about it):
IEnumerable<string> checkedItems = ProductTypesList.CheckedItems.Cast<string>();
filter = p => checkedItems.Contains(p.ProductType);
So OK, yes, I already realize this. However, I'm posting the question anyway, because I still don't quite get why what I was (stupidly) trying to do wasn't working.
I thought this would be extremely easy. Turns out it is giving me quite a headache.
The basic idea: display all the items whose ProductType property value is checked in a CheckedListBox.
The implementation:
private Func<Product, bool> GetProductTypeFilter() {
// if nothing is checked, display nothing
Func<Product, bool> filter = p => false;
foreach (string pt in ProductTypesList.CheckedItems.Cast<string>()) {
Func<Product, bool> prevFilter = filter;
filter = p => (prevFilter(p) || p.ProductType == pt);
}
return filter;
}
However, say the items "Equity" and "ETF" are both checked in ProductTypesList (a CheckedListBox). Then for some reason, the following code only returns products of type "ETF":
var filter = GetProductTypeFilter();
IEnumerable<Product> filteredProducts = allProducts.Where(filter);
I guessed it might have had something to do with some self-referencing messiness where filter is set to, essentially, itself or something else. And I thought that maybe using ...
filter = new Func<Product, bool>(p => (prevFilter(p) || p.ProductType == pt));
...would do the trick, but no such luck. Can anybody see what I am missing here?

I believe you have a modified closure problem here. The pt parameter is bound into the lambda expression but changes as the loop progresses. It's important to realize the when a variable is referenced in a lambda it is the variable that is captured, not the value of the variable.
In loops this has a very significant ramification - because the loop variable is changing, not being redefined. By creating a variable inside the loop, you are creating a new variable for each iteration - which then alows the lambda to capture each independently.
The desired implementation would be:
foreach (string pt in ProductTypesList.CheckedItems.Cast<string>()) {
string ptCheck = pt;
Func<Product, bool> prevFilter = filter;
filter = p => (prevFilter(p) || p.ProductType == ptCheck);
}
Eric Lippert has written about this specific situation:
http://blogs.msdn.com/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx
http://blogs.msdn.com/ericlippert/archive/2009/11/16/closing-over-the-loop-variable-part-two.aspx
Also, see the question Access to Modified Closure (2) for a good explanation of what happens with closure variables. There's also an series of articles on the blog The Old New Thing that has an interesting perspective on this:
http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx
http://blogs.msdn.com/oldnewthing/archive/2006/08/03/687529.aspx
http://blogs.msdn.com/oldnewthing/archive/2006/08/04/688527.aspx

It has to do with closures. The variable pt will always refer to the last value of the for loop.
Consider the following example where the output is the one expected because it's using a variable that is scoped inside the for loop.
public static void Main(string[] args)
{
var countries = new List<string>() { "pt", "en", "sp" };
var filter = GetFilter();
Console.WriteLine(String.Join(", ", countries.Where(filter).ToArray()));
}
private static Func<string, bool> GetFilter()
{
Func<string, bool> filter = p => false;
foreach (string pt in new string[] { "pt", "en" })
{
Func<string, bool> prevFilter = filter;
string name = pt;
filter = p => (prevFilter(p) || p == name);
}
return filter;
}

Since you're looping and setting the filter type to itself, you're setting the product type to the last pt in each case. It's a modified closure and since it's delay bound, you need to copy it on each loop, like this:
foreach (string pt in ProductTypesList.CheckedItems.Cast<string>()) {
var mypt = pt;
Func<Product, bool> prevFilter = filter;
filter = p => (prevFilter(p) || p.ProductType == mypt);
}
This should result in the right result, otherwise the last pt is used for all equality checks.

Related

Dynamic lambda parameters based on dictionary elements

My plan is to create a query, but the parameters based on a Dictionary.
The Dictionary contains string key and bool value.
Can be 2 or 3 or more items in the dictionary.
Dictionary<string, bool> items = new Dictionary<string, bool>();
items.Add("CostFree", true);
items.Add("Visible", true);
items.Add("Closed", true);
This is the dictionary I am sending and based on this I want to create dynamically a query like
.Where(e => e.CostFree == true || Visible == true || Closed == true)
but the dictionary can contain 2, 3 or four items.
How can I solve this ?
Thanks in advance
LINQ expressions can be built easily via static methods exposed on System.Linq.Expressions.Expression class.
Here is a sample with your needs assuming the entity you are building the expression against named SomeClass
[TestMethod]
public void MyTestMethod()
{
var testData = new List<SomeClass>()
{
new SomeClass() {Id=1, CostFree = false, Closed='N', Visible=false},
new SomeClass() {Id=2, CostFree = true, Closed='N', Visible=false}, // expect only this one matching
};
var items = new Dictionary<string, object>();
items.Add("CostFree", true);
items.Add("Visible", true);
items.Add("Closed", 'Y');
// this one will be the "e" in "e => e.CostFree == true || Visible == true || Closed == 'Y'"
var paramExpression = Expression.Parameter(typeof(SomeClass));
// lets construct the body ("e.CostFree == true || Visible == true || Closed == 'Y'") part step-by-step
// the parts consists of binary "equals" expressions combined via logical "or" expression
var bodyExpression = (Expression)null;
foreach(var kvp in items)
{
// get the named property ("CostFree", ...) reference of paramExpression. this is the left hand side of "equals"
var propertyExpression = Expression.PropertyOrField(paramExpression, kvp.Key);
// get the constant with appropriate value to place on right hand side of "equals"
var constantExpression = Expression.Constant(kvp.Value, kvp.Value.GetType());
// combine them into "equals"
var binaryEqualsExpression = Expression.Equal(propertyExpression, constantExpression);
if (bodyExpression == null)
{
bodyExpression = binaryEqualsExpression;
}
else
{
// combine each "equals" parts with logical "or"
bodyExpression = Expression.OrElse(bodyExpression, binaryEqualsExpression);
}
}
// now construct the whole lambda...
var lambdaExpression = Expression.Lambda<Func<SomeClass, bool>>(bodyExpression, paramExpression);
// ...and make it useable in .Where()
var compiledExpression = lambdaExpression.Compile();
// lets execute in on our test data
var r = testData.Where(compiledExpression);
// only #2 should match
Assert.AreEqual(2, r.Single().Id);
}
Update:
I changed the solution:
items values are of type object
constantExpression honors the value's type.
This way the dictionary can contain other name-value pairs and the solution
still works. The rule of dictionary contents: keys must match SomeClass property names and values must match the given property's type.
The easy (but inelegant) way of doing this is to chain a series of Union statements. You can use a lookup dictionary with a key matching your strings and a value containing an appropriate predicate.
Here is an example using an extension method:
static public IQueryable<Foo> WithFlags(this IQueryable<Foo> source, string[] flags)
{
var map = new Dictionary<string, Expression<Func<Foo, bool>>>()
{
{ "Closed", x => x.Closed },
{ "CostFree", x => x.CostFree },
{ "Visible", x => x.Visible }
};
//Start with a query that returns nothing
var query = source.Where(x => false);
//For each flag supplied by the caller, add an additional set
foreach (var flag in flags)
{
query = query.Union(query.Where(map[flag]));
}
return query;
}
To use:
var results = DbContext.Foo.WithFlags( new string[] { "Closed", "Visible" }).ToList();
The more elegant way to do it is to build a predicate expression containing Or logic. This would be a little involved. I recommend finding a third party toolkit. See this answer.

Difficulty typing arguments for System.Linq.Enumerable.Select

I've been staring at this for awhile and not sure how to fix it.
All I'm trying to do is fill in the arptable description property where it matches the address in the device table. I am not trying to create another collection from the arptable.
Error:
The type arguments for method 'System.Linq.Enumerable.Select(System.Collections.Generic.IEnumerable, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Here is the offending code:
IEnumerable<ARPTABLE> GetARPTable()
{
IpTable arp = new IpTable();
IEnumerable<ARPTABLE> arptable = arp.GetArpTable();
arptable.ToList().ForEach(i =>
{
DeviceTable.Where(j => j.PhysicalAddress == i.MAC)
.Select(y =>
{
i.Description = y.Model ?? y.DeviceName;
});
});
return arptable;
}
where DeviceTable is
public ObservableCollection<Device> DeviceTable { get; set; }
Thanks for any help (or a better way).
The compiler is having trouble because your lambda expression isn't written correctly and so it fails on type inference. Unfortunately, the whole construction of the method is broken and I'm not sure I really understand what you're trying to accomplish here.
But in terms of getting it to compile, your method should look more like this:
IEnumerable<ARPTABLE> GetARPTable()
{
IpTable arp = new IpTable();
IEnumerable<ARPTABLE> arptable = arp.GetArpTable();
foreach (var i in arptable)
{
Device j = DeviceTable.FirstOrDefault(j => j.PhysicalAddress == i.MAC);
if (j != null)
{
i.Description = j.Model ?? j.DeviceName;
}
}
return arptable;
}
As a general note: do not use methods like Select() as a way to simply visit each element in the collection. The expression you give to the Select() method will not actually be evaluated unless you evaluate the IEnumerable<T> that was returned, which you did not in this case. And even if you do evaluate the IEnumerable<T>, it's an inefficient misuse of the method.
Also, while List<T>.ForEach() could be considered convenient by some, it is wasteful to convert an IEnumerable<T> to a List<T> just for the purpose of calling that method. A regular foreach statement works fine and is more efficient.
LINQ is not ment to be used for filling in data. It's a query language and so the Select method returns a new sequence. Just do it with foreach. I would image it could look like this, although I'm not exactly sure if I got the logic right.
foreach(var table in arptable)
{
var device = DeviceTable.SingleOrDefault(...);
if (device != null)
{
table.Description = device.Model ?? device.DeviceName;
}
}
As for your current form
arptable.ToList().ForEach(i =>
this is really not necessary, why cast the sequence to list if you don't have to? Just to use that ForEach? We can do better.
DeviceTable.Where(j => j.PhysicalAddress == i.MAC)
.Select(y => i.Description = y.Model ?? y.DeviceName);
This returns a new sequence, which you are not storing in any local variable. LINQ queries should not have side effect, it's against the lambda calculus, the idea behind LINQ itself.
i like the other answers. if you still want to use linq, this is how you would:
IEnumerable<ARPTABLE> GetARPTable()
{
IpTable arp = new IpTable();
IEnumerable<ARPTABLE> arptable = arp.GetArpTable();
arptable = arptable.Select(i =>
{
Device device = DeviceTable.SingleOrDefault(j => j.PhysicalAddress == i.MAC);
if (device != null)
{
i.Description = device.Model ?? device.DeviceName;
}
return i;
});
return arptable;
}

Using nested Any() method

Suppose you wanna test or compare the equality of two Vectors.
Suppose you have:
string[] models = {"ModelOne", "ModelTwo", "ModeThree"};
And another one that you don't know for sure what will be inside of it, but you believe that it will contain the same elements like models owner above.
I have this method to make this verification and I use it in a Unit test passing the vector models presented above.
public bool TemplateForDependenciesTests (string[] v)
{
var dependency = new Dependencies();
var result = dependency.GetByReferencedModel(typeof(T).ToString());
//foreach (var i in result)
//{
//if ((v.Any(model => model == i.ReferencingModelName)))
//return false;
//}
return result.Any(x => (v.Any(model => model == x.ReferencingModelName)));
}
the result variable will hold the return of this method:
public IEnumerable<Dependency> GetByReferencedModel(string referencedModelName)
{
return this.dependencies
.Where(d => d.ReferencedModelName == referencedModelName);
}
The question is: How can I make that return statement in TemplateForDependenciesTests() work nicely and in a way I can snoop that indeed it is doing what I expect, because till now I moved some stones here and there, but it appears not doing what I want?
It looks like you're just trying to see if any member of result has a ReferencingModelName that's in the models collection. Seems like this would do it:
return result.Select(x => x.ReferencingModelName).Intersect(v).Any();
Now, if you want to snoop to see if it's really doing what you expect:
var intersection = result.Select(x => x.ReferencingModelName).Intersect(v).ToList();
// now you can examine the contents of the intersection list
// and you can return the result
return intersection.Any();
You might even go one step further:
var result = dependency.GetByReferencedModel(typeof(T).ToString()).ToList();
var names = result.Select(x => x.ReferencingModelName).ToList();
var intersection = names.Intersect(v).ToList();
return intersection.Any();
With that, you can examine the results of each step, and you should be able to see where the error exists.
Order doesn't matter to Intersect. That is if you have:
var x = new string["a", "b", "c"];
var y = new string["c", "b"];
var z = new string["b", "c"];
Then x.Intersect(y) == y.Intersect(x) == x.Intersect(z) == y.Intersect(z), etc.
You could make your lambdas easier to debug by making them multi-line statements. E.g. you could put breakpoints all over this to see exactly what's happening.
var resultList = result.ToList();
return resultList.Any(x =>
{
bool outer = v.Any(model =>
{
bool inner = model == x.ReferencingModelName;
return inner;
});
return outer;
});
I'll also note that with things like ToLookup or ToDictionary, and HashSet<T>, you could make all of these lookups much faster and more intuitively-coded.

Linq, using ToLookup to project values to different named variables

var tmpProjection = myCollection.ToLookup(t => t.SomeBoolValue);
var listOneFinal = tmpProjection[true];
var listTwo = tmpProjection[false];
First question, is there a way to assign it to listOne and listTwo in some shorter way, I know I'm being pedantic here, ... just asking.
Now,
var listThree = listTwo.ToLookup(t => t.SomeOtherBoolValue);
var listFourFinal = listThree[false];
var listFiveFinal = listThree[true];
So in thise case, I just need (ultimately) listOneFinal, listFourFinal and listFiveFinal -- but i'm creating this temp stuff in between ... is there a way to reduce this.
i'm only talk code-wise not performance or code criticality.
bool is kind of weak for communicating intent. Int is a little better and enum would be best.
Lookup<int, T> myLookup = myCollection
.ToLookup(t =>
t.someBoolValue ? 1 :
t.someOtherBoolValue ? 4 :
5
);
var listOne = myLookup[1];
var listFour = myLookup[4];
var listFive = myLookup[5];
You can do it in fewer statements, but since you need to end op with 3 values, you need at least 3 assignments. Your code is very readable, don't sacrifice readability for "being smart" and reducing to fewer statements. That being said, here is a 3 - statement version; that will work well if collections are small (your own version will perform better with larger collections, since this version iterates multiple times through the collection):
var listOneFinal = myCollection.Where(t => t.SomeBoolValue);
var listFourFinal = myCollection.Where(t => !t.SomeBoolValue && !t.SomeOtherBoolValue);
var listFiveFinal = myCollection.Where(t => !t.SomeBoolValue && t.SomeOtherBoolValue);
Depending on your real usage scenario, the above might be more readable.
I think what you've got there is pretty good already, to be honest.
If you're simply looking to minimize the number of statements, I doubt you could do better than:
var listOneFinal = myCollection.Where(t => t.SomeBoolValue);
var listFourFinal = myCollection.Where(t => !t.SomeBoolValue && !t.SomeOtherBoolValue);
var listFiveFinal = myCollection.Where(t => !t.SomeBoolValue && t.SomeOtherBoolValue);
Or perhaps:
var predicates = new Func<MyClass,bool>[]{ t => t.SomeBoolValue, t => t.SomeOtherBoolValue};
var listOneFinal = myCollection.Where(predicates.First());
var listFourFinal = myCollection.Where(t => !predicates.Any(p => p(t)));
var listFiveFinal = myCollection.Where(t => !predicates[0](t) && predicates[1](t));
(Call ToList() on each query if desired)
But really, I prefer your technique much better, the code I have provided is not particularly more readable or efficient.
You might want to consider just storing the 2 lookups instead of each list and inline each 'final lookup' where necessary since it's cheap to call Lookup[key]. So whenever you need listFourFinal, just call listThree[false]. Better variable names would help, obviously.
If you find yourself doing this often, you can write a function to do it. For a boolean ToLookup, we can use C#'s out parameters to return multiple values.
public static void Dichotomize<T>(this IEnumerable<T> source,
Func<T,bool> keySelector,
out IEnumerable<T> affirmative,
out IEnumerable<T> negative) {
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
var affirmativeList = new List<T>();
var negativeList = new List<T>();
foreach (var element in source) {
(keySelector(element) ? affirmativeList : negativeList).Add(element);
}
affirmative = affirmativeList.AsReadOnly();
negative = negativeList.AsReadOnly();
}
Now we can do:
IEnumerable<T> listOneFinal, listTwo, listFourFinal, listFiveFinal;
myCollection.Dichotomize(t => t.SomeBoolValue, out listOneFinal, out listTwo);
listTwo.Dichotomize(t => t.SomeOtherBoolValue, out listFiveFinal, out listFourFinal);

Difference between two "where"s in LINQ

Kindly let me know the difference between the "where" in (1) and "where()" in (2).
When to use "where" and "where()" ?
List<Person> pList =
new List<Person>
{
new Person
{EmpNo=1,FirstName="Marc",LastName="Loel",Salary=3434},
new Person
{EmpNo=2, FirstName="Steve",LastName="Kaith",Salary=4545},
new Person
{EmpNo=3,FirstName="Neol",LastName="Henk",Salary=2222},
};
(1) var v = from p in pList where p.EmpNo == 1 select new { p.FirstName };
(2) var query =pList .Where(p => p.EmpNo == 1)
.Select(p => new { p.FirstName});
The difference is that one form is easier to read and the other form is more difficult to read. Trouble is, about half the people think the first one is easier, and half the people think the second one is the easier one! Choose the one you like best and stick with it; they mean exactly the same thing.
There is no real difference. The first where (and select) are a special in-language query expression that get translated by the compiler into those other lambda-based Where and Select methods.
It's just syntactic sugar. In fact, if you just have a class with the correct Where method, even if the class isn't enumerable, you can use the syntactic magic:
class MyClass
{
public IQueryable<int> Where(Func<int, bool> predicate)
{
return Enumerable.Range(1, 100).AsQueryable();
}
}
static void Main(string[] args)
{
var q = from p in new MyClass()
where p == 10
select p;
}
This doesn't do anything, but it builds and will call that method.
I believe they are identical. Microsoft created the syntax in (1) for readability, but the compiler handles it as (2).
There is no difference. Number (1) is just written with some syntactic sugar.
Quick look at the code in reflector and it looks like this:
var v = pList.Where<Person>(delegate (Person p) {
return (p.EmpNo == 1);
}).Select(delegate (Person p) {
return new { FirstName = p.FirstName };
});
var query = pList.Where<Person>(delegate (Person p) {
return (p.EmpNo == 1);
}).Select(delegate (Person p) {
return new { FirstName = p.FirstName };
});
As you can see, they are exactly the same.
The difference (if you want to be picky) is that the first one is LINQ, and the second one isn't.
LINQ is the integrated query language that you see in the first example, and the compiler turns it into using the extension methods seen in the second example.
There are some additional features in.where () method e.g. you can use index extension of where method.
But for given example its just readability.

Categories

Resources