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のもの) の1 つを使用し、置き換えることを検討してください。

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 関数を 1 回だけ実行するよりも効率が悪いことに注意してください。

于 2013-07-09T19:00:43.313 に答える
-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 に答える