3

我正在寻找一种简单的方法来删除重复项,而不必实现 IComparable 类,不必重写 GetHashCode 等。

我认为这可以通过 linq 来实现。我有课:

class Person
{
    public string Name;
    public ing Age;
}

我有一个大约 500 人的列表List<Person> someList = new List<Person()

现在我想删除同名的人,如果有重复,我想保留年龄较大的人。换句话说,如果我有清单:

Name----Age---
Tom,     24  |
Alicia,  22  |
Alicia,  12  |

我想结束:

Name----Age---
Tom,     24  |
Alicia,  22  |

我如何通过查询来做到这一点?我的列表没有那么长,所以我不想创建哈希集也不想实现 IComparable 接口。如果我可以使用 linq 查询来做到这一点,那就太好了。

我认为这可以通过 groupBy 扩展方法通过执行以下操作来完成:

var people = // the list of Person
person.GroupBy(x=>x.Name).Where(x=>x.Count()>1)
      ...    // select the person that has the greatest age...
4

4 回答 4

8
people
  .GroupBy(p => p.Name)
  .Select(g => g.OrderByDescending(p => p.Age).First())

这将适用于不同的 Linq 提供程序。如果这只是 Linq2Objects,并且速度很重要(通常不是),请考虑使用 Web 上的许多 MaxBy 扩展之一(这里是Skeet的)并替换

g.OrderByDescending(p => p.Age).First()

g.MaxBy(p => p.Age)
于 2013-07-09T18:59:51.060 回答
3

只要您首先创建一个MaxBy能够从选择器最大的序列中选择项目的辅助函数,这将非常容易。不幸的是Max,LINQ 中的函数不起作用,因为我们想从序列中选择项目,而不是选择的值。

var distinctPeople = people.GroupBy(person => person.Name)
   .Select(group => group.MaxBy(person => person.Age));

然后执行MaxBy

public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector, IComparer<TKey> comparer = null)
{
    comparer = comparer ?? Comparer<TKey>.Default;

    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
            throw new ArgumentException("Source must have at least one item");

        var maxItem = iterator.Current;
        var maxKey = keySelector(maxItem);

        while (iterator.MoveNext())
        {
            var nextKey = keySelector(iterator.Current);
            if (comparer.Compare(nextKey, maxKey) > 0)
            {
                maxItem = iterator.Current;
                maxKey = nextKey;
            }
        }

        return maxItem;
    }
}

请注意,虽然您可以通过对序列进行排序然后获取第一项来获得相同的结果,但这样做通常比使用 max 函数执行一次传递效率低。

于 2013-07-09T19:00:43.313 回答
0

我更喜欢简单:

var retPeople = new List<Person>;
        foreach (var p in person)
        {
            if(!retPeople.Contains(p))
            {
                retPeople.Add(p);
            }
        }

使人实现 IComparable

于 2013-07-11T05:52:48.383 回答
-1

我摆脱了我的最后一个答案,因为我意识到它太慢而且太复杂了。这是更有意义的解决方案

        var peoplewithLargestAgeByName =
            from p in people
            orderby p.Name
            group p by p.Name into peopleByName
            select peopleByName.First ( );

这与@spender 贡献的解决方案相同,但使用的是 linq 语法。

于 2013-07-09T19:02:39.197 回答