19

C#にオブジェクトのList <>があり、リスト内で重複していると見なされるオブジェクトを返す方法が必要です。Distinct結果セットは必要ありません。リポジトリから削除するアイテムのリストが必要です。

この例のために、「車」タイプのリストがあり、これらの車のどれがリスト内の別の車と同じ色であるかを知る必要があるとします。リスト内の車とその色のプロパティは次のとおりです。

Car1.Color = Red;

Car2.Color = Blue;

Car3.Color = Green;

Car4.Color = Red;

Car5.Color = Red;

この例では、結果(IEnumerable <>、List <>など)にCar4とCar5を含める必要があります。これは、リポジトリまたはデータベースからこれらを削除して、リポジトリに色ごとに1台の車しか持たないようにするためです。どんな助けでもいただければ幸いです。

4

8 に答える 8

29

昨日、「射影による区別」を書こうとしていたときに、うっかりしてこれをコーディングしてしまいました。を含めました!あるべきではないときですが、今回はちょうどいいです:

public static IEnumerable<TSource> DuplicatesBy<TSource, TKey>
    (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> seenKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        // Yield it if the key hasn't actually been added - i.e. it
        // was already in the set
        if (!seenKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}

次に、次のように呼び出します。

var duplicates = cars.DuplicatesBy(car => car.Color);
于 2009-01-29T22:21:44.070 に答える
17
var duplicates = from car in cars
                 group car by car.Color into grouped
                 from car in grouped.Skip(1)
                 select car;

これにより、車が色別にグループ化され、各グループの最初の結果がスキップされ、各グループの残りが 1 つのシーケンスにフラット化されて返されます。

どれを維持したいかについて特定の要件がある場合、たとえば、車にIdプロパティがあり、車を最低の で維持したい場合Id、そこに順序を追加できます。

var duplicates = from car in cars
                 group car by car.Color into grouped
                 from car in grouped.OrderBy(c => c.Id).Skip(1)
                 select car;
于 2009-01-29T22:27:41.657 に答える
5

これは、あなたが何をしようとしているのかをより明確にする、わずかに異なるLinqソリューションです。

var s = from car in cars
    group car by car.Color into g
    where g.Count() == 1
    select g.First();

これは、車を色でグループ化し、複数の要素を持つすべてのグループを破棄し、残りを返されたIEnumerableに入れるだけです。

于 2009-01-30T14:51:25.120 に答える
3
IEnumerable<Car> GetDuplicateColors(List<Car> cars)
{
    return cars.Where(c => cars.Any(c2 => c2.Color == c.Color && cars.IndexOf(c2) < cars.IndexOf(c) ) );
}    

基本的には、「リストに同じ色で小さいインデックスの車がある場合は、車を返す」ことを意味します。

性能は定かではありませんが。重複の O(1) ルックアップ (ディクショナリ/ハッシュセット メソッドなど) を使用したアプローチは、大規模なセットの場合により高速になる可能性があると思われます。

于 2009-01-29T22:11:00.113 に答える
3

を新規作成しDictionary<Color, Car> foundColorsList<Car> carsToDelete

次に、元の車のリストを次のように繰り返し処理します。

foreach(Car c in listOfCars)
{
    if (foundColors.containsKey(c.Color))
    {
        carsToDelete.Add(c);
    }
    else
    {
        foundColors.Add(c.Color, c);
    }
}

次に、foundColors にあるすべての車を削除できます。

新しいリストを作成する代わりに「レコードの削除」ロジックをステートメントに入れることで、パフォーマンスをわずかに向上させることができますがif、質問の言い方から、リストにそれらを収集する必要があることが示唆されました。

于 2009-01-29T22:11:23.843 に答える
0

実際にコーディングせずに、次のようなアルゴリズムはどうでしょうか。

  • List<T>作成を繰り返しますDictionary<T, int>
  • が> 1Dictionary<T, int>のエントリを削除することを繰り返しますint

に残っているものDictionaryはすべて重複しています。もちろん、実際に削除する 2 番目の部分はオプションです。を反復処理してDictionary、>1 を探してアクションを実行できます。

編集: OK、Ryan が実際にコードを提供してくれたので、Ryan に連絡を取りました。;)

于 2009-01-29T22:12:16.960 に答える
0

public static IQueryable Duplicates (この IEnumerable ソース) where TSource : IComparable {

if (source == null)   
     throw new ArgumentNullException("source");   
 return source.Where(x => source.Count(y=>y.Equals(x)) > 1).AsQueryable<TSource>();   

}

于 2009-01-30T15:02:42.380 に答える
0

私の回答は、フォロワーの回答者 (Joe Coehoorn、Greg Beech、Jon Skeet) から (この順序で) インスピレーションを得ています。

完全な例を提供することにしました。(実際の効率のために) 車の色の静的なリストがあることを前提としています。次のコードは、必ずしも超効率的であるとは限りませんが、洗練された方法で問題の完全な解決策を示していると思います。

#region SearchForNonDistinctMembersInAGenericListSample
public static string[] carColors = new[]{"Red", "Blue", "Green"}; 
public static string[] carStyles = new[]{"Compact", "Sedan", "SUV", "Mini-Van", "Jeep"}; 
public class Car
{
    public Car(){}
    public string Color { get; set; }
    public string Style { get; set; }
}
public static List<Car> SearchForNonDistinctMembersInAList()
{
    // pass in cars normally, but declare here for brevity
    var cars = new List<Car>(5) { new Car(){Color=carColors[0], Style=carStyles[0]}, 
                                      new Car(){Color=carColors[1],Style=carStyles[1]},
                                      new Car(){Color=carColors[0],Style=carStyles[2]}, 
                                      new Car(){Color=carColors[2],Style=carStyles[3]}, 
                                      new Car(){Color=carColors[0],Style=carStyles[4]}};
    List<Car> carDupes = new List<Car>();

    for (int i = 0; i < carColors.Length; i++)
    {
        Func<Car,bool> dupeMatcher = c => c.Color == carColors[i];

        int count = cars.Count<Car>(dupeMatcher);

        if (count > 1) // we have duplicates
        {
            foreach (Car dupe in cars.Where<Car>(dupeMatcher).Skip<Car>(1))
            {
                carDupes.Add(dupe);
            }
        }
    }
    return carDupes;
}
#endregion

後でここに戻ってきて、スタイルを対比するために、このソリューションを 3 つのインスピレーションすべてと比較します。かなり興味深いです。

于 2009-01-30T01:48:07.867 に答える