linq 在C#中根据重复项的属性之一从列表中删除重复项

ih99xse1  于 2023-01-18  发布在  C#
关注(0)|答案(6)|浏览(185)

我有类型的类列表:

public class MyClass
{        
    public SomeOtherClass classObj;         
    public string BillId;           
}

public List<MyClass> myClassObject;

样本值:

BillId = "123",classObj = {},
BillId = "999",classObj = {},
BillId = "777",classObj = {},
BillId = "123",classObj = {}

在上面的例子中,我们有BillId的重复值。我想删除所有重复值(不区分),这样结果将只包含999777值。
实现这一点的一种方法是

  • 循环遍历所有项目
  • 获取唯一BillId的计数
  • 如果count大于1,则将BillId存储在另一个变量中
  • 再次循环并基于BillId移除项目

有没有直接的方法可以达到这个目的?

klsxnrf1

klsxnrf11#

我想这是可行的:

var result = myClassObject.GroupBy(x => x.BillId)
    .Where(x => x.Count() == 1)
    .Select(x => x.First());

小提琴here

rggaifut

rggaifut2#

你也可以这么做,

var result = myClassObject.GroupBy(x => x.BillId)
              .Where(x => !x.Skip(1).Any())
              .Select(x => x.First());
    • 一个
moiiocjp

moiiocjp3#

这可能会有帮助。

var result = myClassObject
          .GroupBy(x => x.BillId)
          .Where(x => x.Count()==1)
          .Select(x => x.FirstOrDefault());
cczfrluj

cczfrluj4#

.Where(x => x.Count()==1)对我不好。
您可以尝试:

.GroupBy(x => x.codeLigne).Select(x => x.First()).ToList()
yc0p9oo0

yc0p9oo05#

试试这个。

var distinctList = myClassObject.GroupBy(m => m.BillId)
                                .Where(x => x.Count() == 1)
                                .SelectMany(x => x.ToList())
                                .ToList();
hujrc8aj

hujrc8aj6#

您需要一个简单明了的解决方案来解决这个问题,GroupBy + Where + Select解决方案可以完美地满足这个需求,但是您可能也会对高性能和内存效率的解决方案感兴趣。下面是一个使用当前可用的所有工具(. NET 6+)来实现最大效率的实现:

/// <summary>
/// Returns a sequence of elements that appear exactly once in the source sequence,
/// according to a specified key selector function.
/// </summary>
public static IEnumerable<TSource> UniqueBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    IEqualityComparer<TKey> comparer = default)
{
    ArgumentNullException.ThrowIfNull(source);
    ArgumentNullException.ThrowIfNull(keySelector);

    Dictionary<TKey, (TSource Item, bool Unique)> dictionary = new(comparer);
    if (source.TryGetNonEnumeratedCount(out int capacity))
        dictionary.EnsureCapacity(capacity); // Assume that most items are unique

    foreach (TSource item in source)
        CollectionsMarshal.GetValueRefOrAddDefault(dictionary, keySelector(item),
            out bool exists) = exists ? default : (item, true);

    foreach ((TSource item, bool unique) in dictionary.Values)
        if (unique)
            yield return item;
}

TryGetNonEnumeratedCount + EnsureCapacity组合可能会对枚举源时分配的内存量产生重大影响,如果源是大小已知的类型,如List<T>
CollectionsMarshal.GetValueRefOrAddDefault确保每个密钥只被散列一次,这在密钥具有昂贵的GetHashCode实现的情况下会产生影响。
用法示例:

List<MyClass> unique = myClassObject.UniqueBy(x => x.BillId).ToList();

Online demo.
上面的UniqueBy与内置的DistinctBy LINQ运算符的不同之处在于,前者完全消除了所有重复项,而后者保留了每个重复元素的第一个示例。

相关问题