Why can't I use this nested lambda expression? - c#

I'm trying to maintain a list of unique models from a variety of queries. Unfortunately, the equals method of our models are not defined, so I couldn't use a hash map easily.
As a quick fix I used the following code:
public void AddUnique(
List<Model> source,
List<Model> result)
{
if (result != null)
{
if (result.Count > 0
&& source != null
&& source.Count > 0)
{
source.RemoveAll(
s => result.Contains(
r => r.ID == s.ID));
}
result.AddRange(source);
}
}
Unfortunately, this does not work. When I step throught the code, I find that even though I've checked to make sure that there was at least one Model with the same ID in both source and result, the RemoveAll(Predicate<Model>) line does not change the number of items in source. What am I missing?

The above code shouldn't even compile, as Contains expects a Model, not a predicate.
You can use Any() instead:
source.RemoveAll(s => result.Any(r => r.ID == s.ID));
This will remove the items from source correctly.

I might opt to tackle the problem a different way.
You said you do not have suitable implementations of equality inside the class. Maybe you can't change that. However, you can define an IEqualityComparer<Model> implementation that allows you to specify appropriate Equals and GetHashCode implementations external to the actual Model class itself.
var comparer = new ModelComparer();
var addableModels = newSourceOfModels.Except(modelsThatAlreadyExist, comparer);
// you can then add the result to the existing
Where you might define the comparer as
class ModelComparer : IEqualityComparer<Model>
{
public bool Equals(Model x, Model y)
{
// validations omitted
return x.ID == y.ID;
}
public int GetHashCode(Model m)
{
return m.ID.GetHashCode();
}
}

source.RemoveAll(source.Where(result.Select(r => r.ID).Contains(source.Select(s => s.ID))));
The goal of this statement is to make two enumerations of IDs, one for source and one for result. It then will return true to the where statement for each of the elements in both enumerations. Then it will remove any elements that return true.

Your code is removing all the models which are the same between the two lists, not those which have the same ID. Unless they're actually the same instances of the model, it won't work like you're expecting.
Sometimes I use these extension methods for that sort of thing:
public static class CollectionHelper
{
public static void RemoveWhere<T>(this IList<T> list, Func<T, bool> selector)
{
var itemsToRemove = list.Where(selector).ToList();
foreach (var item in itemsToRemove)
{
list.Remove(item);
}
}
public static void RemoveWhere<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, Func<KeyValuePair<TKey, TValue>, bool> selector)
{
var itemsToRemove = dictionary.Where(selector).ToList();
foreach (var item in itemsToRemove)
{
dictionary.Remove(item);
}
}
}

Related

How to change IObservable Func predicates at runtime in C#

I'm new to dynamic data and in general the reactive extension world and I'm currently facing a following problem, where I'd like to change the IObservable<Func<T,bool>> predicates at runtime by using the dynamic data package and thus the reactive extensions in .NET (C#).
Considering the following situation, I have a DataGrid with some columns of type integer, lets say A,B,C. Furthermore, there is a filter UI where the user can add multiple filters, like A == 6 or a combination of filter expressions, like A == 7 || A == 3 || B == 5, etc. So basically my method returning a Func<T, bool> delegate looks like this:
private Func<T, bool> FilterOnA(string id)
{
return n => n.Id == int.Parse(id);
}
And the Filter method call in the data pipeline:
// sourceList is used to fill the ReadOnlyObservableCollection<T> while receiving data from an event pattern
sourceList.Connect() // SourceList<T>
.Filter(filterViewModel.FilterOnA)
.Bind(out _itemsBinding) // private ReadOnlyObservableCollection<T>
.DisposeMany()
.Subscribe();
As I mentioned above, the user shall be able to add/remove/modify and more importanlty combine the filter expressions all together.
Since the dynamic's data Filter method is taking a Func<T,bool> or an IObservable<Func<T,bool>>, one possible solution might look like this:
public IObservable<Func<T,bool>> Filter1 {get;}
public IObservable<Func<T,bool>> Filter2 {get;}
public IObservable<Func<T,bool>> Filter3 {get;}
public IObservable<Func<T,bool>> FilterX {get;}
public IObservable<Func<T,bool>> AllFiltersCombined => Filter1.CombineLatest(Filter2,Filter3,FilterX, (f1,f2,f3,fx) => AggregatePredicatesAnd(f1,f2,f3,fx));
public static Func<T,Bool> AggregatePredicatesAnd(params Func<T,bool>[] predicates)
{
return predicates.Aggregate<Func<T,bool>>((fa,fb) => (T t) => fa(t) && fb(t));
}
Now, my problem is, how to write this in a more generic way? How to combine for e.g. 0 to n Filters? And what is about different filter types, e.g. a combination of A <= 7 && A != 5?
You could use something like the ApplyFilters operation shown here:
public static class Extensions
{
public static List<T> Apply<T>(this List<T> list, Action<List<T>> action)
{
action(list);
return list;
}
public static IObservable<T> ApplyFilters<T>(this IObservable<T> source, IObservable<Func<T, bool>> AddFilter, IObservable<Func<T, bool>> RemoveFilter)
{
// Project AddFilter to a func that adds a filter to a list of filters
var adding = AddFilter.Select(func => (Action<List<Func<T, bool>>>)(list => list.Add(func)));
// Project RemoveFilter to a func that removes a filter from a list of filters
var removing = RemoveFilter.Select(func => (Action<List<Func<T, bool>>>)(list => list.Remove(func)));
// Return an observable that...
return Observable
// ... merges the add and remove operations ...
.Merge(adding, removing)
// ... and applies them to an initially empty list ...
.Scan(new List<Func<T, bool>>(), (list, change) => list.Apply(change))
// ... and project every list change to a new observable
// by applying all operations to the source observable ...
.Select(list => list.Aggregate(source, (s, f) => s.Where(f)))
// ... and finally subscribing to the new observable
.Switch();
}
}
public class ViewModel
{
public IObservable<Item> _source;
public IObservable<Func<Item, bool>> _addFilter;
public IObservable<Func<Item, bool>> _removeFilter;
public ViewModel()
{
FilteredItems = _source.ApplyFilters(_addFilter, _removeFilter);
}
public IObservable<Item> FilteredItems { get; }
}
public class Item { }
Limitations:
No consideration has been made regarding Func<T, bool> equivalence. You may need to strongly type each filter func to ensure it's able to be added / removed from the internal list of filters correctly.
No consideration has been made regarding grouping && and || operations (i.e. (A == 7 && B == "Hello") || C == -1)). If this is important you will definitely need to strongly type the filters (per 1) and add a group identifer. You could then use a GroupBy on the List prior to performing an Aggregate on the observable.
In contrast to ibeebs answer, I've also discovered another possible solution. In order to build possible combinations of filters, one might use the Dynamic Expressions lib: https://github.com/zzzprojects/System.Linq.Dynamic/wiki/Dynamic-Expressions
and create expressions like this one:
Expression<Func<T, bool>> e2 = DynamicExpression.ParseLambda<T, bool>("Id == 7 or Id == 9");
or more complex ones.
Since I've mentioned in my question that the User is able to create the filters via UI, it is not a big deal then to build string expressions like "Id == 7 or Id == 9".
Such Expression can be simply compiled to a Func<T, bool>.

Abstracting LINQ order query to multi level sort function

I would like to make a sorting extension method which will take a Generic Collection and sort it using one or more keys. The keys will be properties of the collection's containing objects.
A sample LINQ query with 3 keys looks like this.
studentResults.OrderBy(x => x.CG).ThenBy(x => x.Student.Roll)
.ThenBy(x => x.Student.Name).ToList();
I have already found something which can do this with one key.
public static List<TSource> OrderByAsListOrNull<TSource, TKey>(
this ICollection<TSource> collection, Func<TSource,TKey> keySelector)
{
if (collection != null && collection.Count > 0) {
return collection
.OrderBy(x => keySelector(x))
.ToList();
}
return null;
}
I thought of using IEnumerable<Func<TSource, TKey> keySelector>, but I cannot call the function like that.
So, how may I implement a method of this kind?
In theory, you could build a multi-levelled sort extension, which diffentiates between the initial OrderBy and the subsequent ThenBys for secondary, tertiary sorting tiebreakers. Since by taking multiple order functions, each of which could reference a different type, you'll need to soften the projected type (I've used object, below).
public static class Extensions
{
public static IEnumerable<T> MyOrderBy<T>(
this IEnumerable<T> source,
params Func<T, object>[] orders)
{
Debug.Assert(orders.Length > 0);
var sortQuery = source.OrderBy(orders[0]);
foreach(var order in orders.Skip(1))
{
sortQuery = sortQuery.ThenBy(order);
}
return sortQuery;
}
}
public class Poco
{
public string Name {get; set;}
public int Number {get; set;}
}
void Main()
{
var items = new []{
new Poco{Name = "Zebra", Number = 99},
new Poco{Name = "Apple", Number = 123}};
foreach(var poco in items.MyOrderBy(i => i.Number, i => i.Name))
{
Console.WriteLine(poco.Name);
}
}
The problem with this (as with your original function) is that you'll probably want to order by descending at some point. Although for numeric sort functions this could be hacked by passing a *-1, it's going to be really difficult to do this for an arbitrary type
// Hack : Order a numeric descending
item => item.Number * -1
For me, I would just stay with Linq's sorting extensions, and not try to abstract them in any way!

Generic Method to get Distinct of LIST<T>

I am trying to compare (values of the properties) a instance of type in a List and eliminate duplicates.
According to MSDN GetHashCode() is one of the way to compare two objects.
A hash code is intended for efficient insertion and lookup in
collections that are based on a hash table. A hash code is not a
permanent value
Considering that, I started writing my extension method as bellow
public static class Linq
{
public static IEnumerable<T> DistinctObjects<T>(this IEnumerable<T> source)
{
List<T> newList = new List<T>();
foreach (var item in source)
{
if(newList.All(x => x.GetHashCode() != item.GetHashCode()))
newList.Add(item);
}
return newList;
}
}
This condition always gives me false though the data of the object is same.
newList.All(x => x.GetHashCode() != item.GetHashCode())
Finally I would like to use it like
MyDuplicateList.DistinctObjects().ToList();
If comparing all fields of the object is too much, I am okay to use it like,
MyDuplicateList.DistinctObjects(x=>x.Id, x.Name).ToList();
Here I am telling compare only these two fields of those objects.
After reading your comments I would propose this solution:
public static IEnumerable<TSource> DistinctBy<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
HashSet<TResult> set = new HashSet<TResult>();
foreach(var item in source)
{
var selectedValue = selector(item);
if (set.Add(selectedValue))
yield return item;
}
}
Then you can use it like this:
var distinctedList = myList.DistinctBy(x => x.A);
or for multiple properties like that:
var distinctedList = myList.DistinctBy(x => new {x.A,x.B});
The advantage of this solution is you can exactly specify what properties should be used in distinction and you don't have to override Equals and GetHashCode for every object. You need to make sure that your properties can be compared.
You shouldn't need to create your own custom, generic method for this. Instead, provide a custom EqualityComparar for your data type:
var myDuplicates = myList.Distinct(new MyComparer());
Where you define a custom Comparer like this:
public class MyComparer : IEqualityComparer<Mine>
{
public bool Equals(Mine x, Mine y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
return x.Name == y.Name && x.Id == y.Id;
}
public int GetHashCode(Mine obj)
{
return obj.Name.GetHashCode() ^ obj.Id.GetHashCode();
}
}
Edit: I initially had incorrect code here, this should do what you want without you having to override an Equals operator

C# - Make a generic foreach method that accepts any type?

Im busy updating an entity using entity framework and web api (on the PUT method of the controller). For each collection property on the updated object, I loop through and check if each item exists in the collection on the existing object or not. If not, I add it.
The trouble is I have a lot of collections on the object and I find myself repeating the following code many times over.
Is there a way for me to wrap this into a generic method and pass that method the 2 collections to compare? Maybe by specifying the name of the property to check and primary key? How would I be able to specify the type for the foreach loop for example?
foreach (HBGender gender in updated.HBGenders)
{
HBGender _gender = existing.HBGenders.FirstOrDefault(o => o.GenderID == gender.GenderID);
if (_gender == null)
{
//do some stuff here like attach and add
}
}
return existing; //return the modified object
Thanks in advance. I hope this makes sense.
In its simplest form you could write an extension method as such:
public static class IEnumerableExtensionMethods
{
public static ICollection<T> ForEachAndAdd<T>(this IEnumerable<T> self,
ICollection<T> other,
Func<T, T, bool> predicate) where T : class
{
foreach(var h1 in self)
{
if(other.FirstOrDefault(h2 => predicate(h1, h2)) == null)
other.Add(h1);
}
return other;
}
}
Usage:
List<HBGender> updated = new List<HBGender>();
List<HBGender> existing = new List<HBGender<();
return updated.ForEachAndAdd(existing, (h1, h2) => h1.Gender == h2.Gender);
Note that if there is extra logic needed during an add, you could add an additonal Action<T> parameter to do so.
I don't know what you are trying to do, but you can play with this example:
List<object> a = new List<object>();
a.Add("awgf");
a.Add('v');
a.Add(4);
foreach (object b in a)
{
Type type = b.GetType().//Select more usefull
Convert.ChangeType(object,type);
}
Just pass your existing check function, as an extra parameter
public List<Class1> Find(List<Class1> updated, List<Class1> existing, Func<Class1, bool> predicate)
{
foreach (Class1 gender in updated)
{
Class1 _gender = existing.FirstOrDefault(predicate); //predicate for quoted example will be o => o.GenderID == gender.GenderID
if (_gender == null)
{
//do some stuff here like attach and add
}
}
return existing;
}

ICombinable .NET Interface

I'm finding myself in need of "combining" several instances of the same type. This type has several IList properties on it. I want to take each instance and combine the values of those IList properties across the instances, so my code only needs one of those instances.
I'm thinking of creating an ICombinable interface, but I'm wonder if there's something already out there that's suited to this?
public interface ICombinable<T>
{
void CombineWith(T instance);
}
Have you tried looking at System.Collections.Generic.HashSet<T>? If you add the same thing multiple times, only 1 item exists.
Sounds like you need Concat
var configs = dbConfig.configList.Concat(fileConfig.configList);
I ended up using SelectMany and Select for this. IConfiguration is an interface for the MyConfigurationInfo class. GetMyConfigurationSources returns all the different IConfigurations (from files, DB, etc).
// accumulates an enumerable property on IConfiguration
public static IEnumerable<TValue> GetConfigurationValues<TValue>(Func<IConfiguration, IEnumerable<TValue>> selector)
{
// cast included for clarification only
return (GetMyConfigurationSources() as IEnumerable<IConfiguration>)
.Where(c => selector(c) != null)
.SelectMany(selector);
}
// accumulates a non enumerable property on IConfiguration
public static IEnumerable<TValue> GetConfigurationValues<TValue>(Func<IConfiguration, TValue> selector)
{
// cast included for clarification only
return (GetMyConfigurationSources() as IEnumerable<IConfiguration>)
.Where(c => selector(c) != null)
.Select(selector);
}
// Example usage:
static void Main()
{
string[] allEnumerableValues = GetConfigurationValues(c => c.SomeEnumerableConfigPropertyOfStrings);
string[] allNonEnumerableValues = GetConfigurationValues(c => c.SomeNonEnumerableConfigPropertyString);
}

Categories