3

次のような形のデータがあります

someArray = [{ Name: "Some Class", TypeEnum: "Default" },
 { Name: "Some Class", TypeEnum: "Other" },
 { Name: "Some Class 2", TypeEnum: "Default" },
 { Name: "Some Class 2", TypeEnum: "Other" },
 { Name: "Some Class 3", TypeEnum: "Default" },
 { Name: "Some Class 4", TypeEnum: "Not Other" }]

それらのそれぞれをC#のオブジェクトとして想像してください

必要なのは、選択したTypeEnumが優先される、その配列の個別のバージョンの配列です。たとえば、otherのTypeEnumを選択した場合でも、「Other」TypeEnumを含むそのクラスのバージョンが見つからない場合は、デフォルトでDefaultに設定します。

たとえば、タイプ列挙型として「その他」を選択すると、上記のデータは次のようになります。

 [{ Name: "Some Class", TypeEnum: "Other" },
 { Name: "Some Class 2", TypeEnum: "Other" },
 { Name: "Some Class 3", TypeEnum: "Default" }]

私が今しているのは、ここからのラムダ比較です

TypeEnum myEnum = "Other"
someArray.Distinct((x,y) => x.Name == y.Name && 
                   x.TypeEnum != myEnum && 
                   (y.TypeEnum == myEnum || y.TypeEnum == "Default"));

Distinctが、その式からtrueを取得する配列から任意のxをポップアウトすることを期待しています。

Distinctが機能すると思う方法が間違っていますか?私がそうなら、代わりに何を使うべきですか?

4

4 に答える 4

2

Comparer<T>次のように、比較のための設定を処理するクラスを定義できます。

public class SomeClassComparer : Comparer<SomeClass>
{
    private TypeEnum _preference;

    public SomeClassComparer(TypeEnum preference)
        : base()
    {
        _preference = preference;
    }

    public override int Compare(SomeClass x, SomeClass y)
    {
        if (x.Name.Equals(y.Name))
        {
            return x.TypeEnum == y.TypeEnum ? 0
                : x.TypeEnum == _preference ? -1
                : y.TypeEnum == _preference ? 1
                : x.TypeEnum == TypeEnum.Default ? -1
                : y.TypeEnum == TypeEnum.Default ? 1
                : x.TypeEnum.CompareTo(y.TypeEnum);
        }
        else
            return x.Name.CompareTo(y.Name);
    }
}

更新:優先またはデフォルトの要素のみに関心がある場合はTypeEnum、最初に残りを除外できます。次に、Comparerに従って配列を並べ替えます。つまりTypeEnum、デフォルトよりも優先順位を高くします。最後に、オブジェクトを名前でグループ化し、各グループから最初のオブジェクトを取得します。

var result = someArray.Where(x => x.TypeEnum == TypeEnum.Default || x.TypeEnum == myEnum)
                      .OrderBy(x => x, new SomeClassComparer(myEnum))
                      .GroupBy(x => x.Name)
                      .Select(x => x.First());

または、Comparerクラスを定義したくない場合は、次のバージョンを使用できます。

Comparison<SomeClass> compareByTypeEnum = (x, y) =>
{
    if (x.Name.Equals(y.Name))
    {
        return x.TypeEnum == y.TypeEnum ? 0
            : x.TypeEnum == myEnum ? -1
            : y.TypeEnum == myEnum ? 1
            : x.TypeEnum == TypeEnum.Default ? -1
            : y.TypeEnum == TypeEnum.Default ? 1
            : x.TypeEnum.CompareTo(y.TypeEnum);
    }
    else
        return x.Name.CompareTo(y.Name);
};
Array.Sort(someArray, compareByTypeEnum);
var result = someArray.Where(x => x.TypeEnum == TypeEnum.Default || x.TypeEnum == TypeEnum.Other)
                      .GroupBy(x => x.Name)
                      .Select(x => x.First());
于 2012-11-09T06:46:34.717 に答える
1

GroupByを使用して、この種の作業を行うための辞書を取得できます。おそらくそれもはるかに簡単です。

List<Tuple<string, string>> lst = new List<Tuple<string, string>>();
lst.Add(new Tuple<string, string>("Some Class", "Default"));
lst.Add(new Tuple<string, string>("Some Class", "Other"));
lst.Add(new Tuple<string, string>("Some Class 2", "Default"));
lst.Add(new Tuple<string, string>("Some Class 2", "Other"));
lst.Add(new Tuple<string, string>("Some Class 3", "Default"));

var dict = lst.GroupBy(g => g.Item1)
              .ToDictionary(g => g.Key, k => k.Select(s => s.Item2)
                                              .Where(p => p == "Other")
                                              .DefaultIfEmpty("Default")
                                              .First());

またはあなたの場合:

TypeEnum myEnum = "Other"
var dict = lst.GroupBy(g => g.Name)
    .ToDictionary(g => g.Key, k => k.Select(s => s.TypeEnum)
                                .Where(p => p == myEnum)
                                .DefaultIfEmpty("Default")
                                .First());
于 2012-11-09T06:49:59.033 に答える
1

Distinctは希望どおりに機能しません。そのため、Distinctを単独で機能させることはおそらく不可能です。Distinctは、ハッシュテーブルを使用して一意の値を検索しています。各アイテムを順番にハッシュテーブルに追加し、ハッシュテーブルにすでに存在する他の値とハッシュが等しい値の追加を省略します。

これは、配列の最初のアイテムが優先されるため、アイテムの順序が重要であることを意味します。ただし、distinctを呼び出す前にリストの順序を変更することで、これを有利に使用できます。@Fungのソリューションを少し変更すると、これが得られます...

var result = someArray.OrderBy(key => key.TypeEnum, new TypeEnumComparer(myEnum))
    .Distinct(new LambdaEqualityComparer<SomeClass>((x, y) => x.Name == y.Name));

変更された比較器で...

public class TypeEnumComparer : Comparer<TypeEnum>
{
    private TypeEnum _preference;

    public TypeEnumComparer(TypeEnum preference)
        : base()
    {
        _preference = preference;
    }

    public override int Compare(TypeEnum x, TypeEnum y)
    {
        if (x == y)                return 0;
        if (x == _preference)      return -1;
        if (y == _preference)      return 1;
        if (x == TypeEnum.Default) return -1;
        if (y == TypeEnum.Default) return 1;

        return x.CompareTo(y);
    }
}
于 2012-11-09T07:18:15.557 に答える
0

これを試して、使用DefaultIfEmpty("Default")

        var someArray = new List<TestClass>
                            {
                                new TestClass {Name = "Some Class", TypeEnum = "Default"},
                                new TestClass {Name = "Some Class", TypeEnum = "Other"},
                                new TestClass {Name = "Some Class 2", TypeEnum = "Default"},
                                new TestClass {Name = "Some Class 2", TypeEnum = "Other"},
                                new TestClass {Name = "Some Class 3", TypeEnum = "Default"}
                            };

        string myEnum = "Other";

        var result = someArray.GroupBy(t => t.Name).
                     Select(t => new TestClass
                       {
                           Name = t.Key,
                           TypeEnum = t.Select(s => s.TypeEnum).Where(p => p == myEnum).DefaultIfEmpty("Default").FirstOrDefault()
                       });
于 2012-11-09T06:46:43.173 に答える