从列表中删除具有最低 Num 属性的重复对象

Remove duplicate objects with lowest Num property from list

我有一个对象列表

public class Obj
{
    public int Num {get;set;}
    public List<string> StrList {get;set;}
    ...other irrelevant properties
}

Obj 列表中的某些项目将包含相同的 StrList,但会有不同的 Num。我想删除列表中具有相似 StrList 的所有 Obj 并保留具有最大 Num.

的那个

这是我的尝试:

objList = objList.GroupBy(x => new { x.StrList }).OrderByDescending(x => x.Select(y => y.Num)).Select(x => x.First()).ToList();

但我收到一个错误:At least one object must implement IComparable.

最好的方法是什么?

  1. 分组时没有理由将列表包装成匿名类型;只需在调用 GroupBy.

  2. 时投影出列表本身
  3. List 没有覆盖 EqualsGetHashCode,因此它将使用列表的引用而不是其内容来定义相等性。您需要创建自定义 IEqualityComparercompare the values of the sequence.

  4. 您正在对组集合进行排序,而这些组没有可比性,因此您的错误。您想要订购每个组 中的项目 。为此,请使用 Select,然后对您要投影的组进行排序(并采用结果查询中的第一个),而不是对外部集合进行排序。

您不能按列表分组,即使是有序列表,但您可以按按特定顺序连接字符串生成的单个字符串分组。假设有一个字符从未出现在任何字符串中(例如,'|'),您可以这样做:

objList = objList
    .GroupBy(x => string.Join("|", x.StrList.OrderBy(s => s)))
    .Select(g => g.OrderByDescending(x => x.Num).First())
    .ToList();

我们的想法是通过按相同顺序(按字典顺序升序)连接各个字符串来构建分组键。

这应该适用于少量数据。如果您的列表非常大,您可以实现一个特殊的 class 用作多部分键进行分组,而无需制作可能很大的键:

public class MultipartKey : IEquitable<MultipartKey> {
    private IList<string> parts;
    int hashCode;
    public MultipartKey(IEnumerable<string> parts) {
        this.parts = parts.OrderBy(s => s).ToList();
        hashCode = this.parts.Aggregate(0, (p, v) => 31*p + v.GetHashCode());
    }
    public override int GetHashCode() {
        return hashCode;
    }
    public override bool Equals(MultipartKey other) {
        return parts.SequenceEqual(other.Parts);
    }
}

并在这样的查询中使用它:

objList = objList
    .GroupBy(x => new MultipartKey(x.StrList))
    .Select(g => g.OrderByDescending(x => x.Num).First())
    .ToList();