1

Consider removing duplicated elements of List from a specific class like below:

private List<MyClass> RemoveDuplicatedMyClass(List<MyClass> myObjects)
{
    List<MyClass> uniqueMyClasses = new List<MyClass>();
    foreach (MyClass item in myObjects)
    {
        if (uniqueMyClasses.FindAll(itm => itm.myAttribute == item.myAttribute).Count == 0)
        {
            uniqueMyClasses.Add(item);
        }
    }
    return uniqueMyClasses;
}

I want to refactor RemoveDuplicatedMyClass to a generic version RemoveDuplicatedItems like below:

public static List<T> RemoveDuplicatedItems<T>(List<T> items, Predicate<T> match)
{
    if (items == null)
    {
        return new List<T>();
    }
    List<T> uniqueItems = new List<T>();
    foreach (T item in items)
    {
        // Check if item exists (= already added)! If not add to unique list.
        if (uniqueItems.FindAll(match).Count < 1)
        {
            uniqueItems.Add(item);
        }
    }
    return uniqueItems;
}

Problem: How can I get access to Predicate<T> match with the inner T item?

Daniel
  • 21
  • 4
  • 2
    Why don't you just use [`Enumerable.Distinct`](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinct)? – Bill Tür stands with Ukraine Dec 22 '22 at 14:37
  • You don't need a `Predicate` but something like a `Func` to map the item to the value to be checked for uniqueness. And then, you can just use [Enumerable.DistinctBy](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinctby?view=net-7.0#system-linq-enumerable-distinctby-2(system-collections-generic-ienumerable((-0))-system-func((-0-1)))), no need to create your own method. – Klaus Gütter Dec 22 '22 at 15:23
  • 1
    If you just need a collection which doesn’t accept duplicates and you you don’t care about order, you can also use a HashSet. The predicate can be provided via an IEqualityComparer implementation. – ckuri Dec 22 '22 at 17:24

2 Answers2

1

As guys mentioned in comments, it's a good idea to use Enumerable.DistinctBy and one solution is to use dynamic objects:

static List<dynamic> RemoveDuplicatedItems(List<dynamic>? items)
{
    if (items == null)
    {
        return new List<dynamic>();
    }
    return items.DistinctBy(x=>x.MyAttribute).ToList();
}

and another and I think better option is to use abstraction, if you have some common properties between your classes you can create interface and define type of T as inheritor of that interface:

static List<T> RemoveDuplicatedItems<T>(List<T>? items) where T:ISomeCommonInterface
{
    if (items == null)
    {
        return new List<T>();
    }
    return items.DistinctBy(x=>x.MyAttribute).ToList();;
}
godot
  • 3,422
  • 6
  • 25
  • 42
0

With help of ckuri this is the correct answer after more research about my problem.

Sidenote: The result can be another IEnumerable to (doesn't have to be List). How to convert List to HashSet in C#? [duplicate]

Daniel
  • 21
  • 4