13

Linq を使用して次のような構造を注文する際に問題があります。

public class Person
{
    public int ID { get; set; }
    public List<PersonAttribute> Attributes { get; set; }
}

public class PersonAttribute
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }
}

人は次のようになります。

PersonAttribute Age = new PersonAttribute { ID = 8, Name = "Age", Value = "32" };
PersonAttribute FirstName = new PersonAttribute { ID = 9, Name = "FirstName", Value = "Rebecca" };
PersonAttribute LastName = new PersonAttribute { ID = 10, Name = "LastName", Value = "Johnson" };
PersonAttribute Gender = new PersonAttribute { ID = 11, Name = "Gender", Value = "Female" };

LINQ プロジェクションを使用して、選択した人物属性で昇順で人物のリストを並べ替えたいと思います。たとえば、Age で並べ替えたり、FirstName で並べ替えたりします。

私は次のようなことを試みています

string mySortAttribute = "Age"
PersonList.OrderBy(p => p.PersonAttribute.Find(s => s.Name == mySortAttribute).Value);

しかし、構文は私に失敗しています。手がかりはありますか?

4

7 に答える 7

8

これが古い投稿であることは承知していますが、他の誰かが必要とする場合に備えて、少し前に見つけた比較ツールを投稿すると思いました。

public class GenericComparer<T> : IComparer<T>
 {
     public string SortExpression { get; set; }
     public int SortDirection { get; set; } // 0:Ascending, 1:Descending

     public GenericComparer(string sortExpression, int sortDirection)
     {
         this.SortExpression = sortExpression;
         this.SortDirection = sortDirection;
     }
     public GenericComparer() { }

     #region IComparer<T> Members
     public int Compare(T x, T y)
     {
         PropertyInfo propertyInfo = typeof(T).GetProperty(SortExpression);
         IComparable obj1 = (IComparable)propertyInfo.GetValue(x, null);
         IComparable obj2 = (IComparable)propertyInfo.GetValue(y, null);

         if (SortDirection == 0)
         {
             return obj1.CompareTo(obj2);
         }
         else return obj2.CompareTo(obj1);
     }
     #endregion
 }

使用法

List<MyObject> objectList = GetObjects(); /* from your repository or whatever */
objectList.Sort(new GenericComparer<MyObject>("ObjectPropertyName", (int)SortDirection.Descending));
dropdown.DataSource = objectList;
dropdown.DataBind();

コンストラクターをオーバーロードして、SortDirection 列挙型を受け入れることができます。クラスが System.Web への参照のないライブラリにあるため、私はこれを行いませんでした。

于 2010-04-22T15:32:47.473 に答える
5

List<PersonAttribute> の代わりにキー値ディクショナリを使用しないのはなぜですか? それはより適していると思いますし、他のすべてをより簡単にします.

更新 - 次のように:

public class Person
{
  public Dictionary<string, string> Attributes = new Dictionary<string,string>();
}

List<Person> people = new List<Person>();

Person rebecca = new Person();
rebecca.Attributes["Age"] = "32";
rebecca.Attributes["FirstName"] = "Rebecca";
rebecca.Attributes["LastName"] = "Johnson";
rebecca.Attributes["Gender"] = "Female";
people.Add(rebecca);

var PeopleInAgeOrder = people.OrderBy(p => p.Attributes["Age"]);
于 2009-03-30T03:28:21.313 に答える
1

これは、Attribute クラスが IComparable を実装しているか、素敵な ToString 関数を持っていることを前提としています (期待しています)。

var list = personList.OrderBy(p => p.Attributes.FirstOrDefault(a => a.Name == "Age"))

そうしないと、構文がさらに複雑になります。

var list = personList
            .OrderBy(p => 
                     p.Attributes.FirstOrDefault(a => a.Name == "Age") == null ?
                     "" : p.Attributes.First(a => a.Name == "Age").Value
            );

また、キーごとに 1 つの値があると仮定します。そうでない場合は、よりスマートなコードが必要になります... ;-)

于 2009-03-30T05:39:45.743 に答える
0

考慮する必要があるいくつかのケース:

  • あなたの属性は文字列であるため、「30」と「3」の年齢は「4」の年齢の前に注文されます
  • 属性が存在しない可能性があります

この拡張メソッド クラスを作成する場合:

public static class ListExtenstions
{
    public static List<Person> OrderList(this List<Person> list, string attributeName, PersonAttribute defaultAttribute)
    {
        return OrderList(list, attributeName, defaultAttribute, x => x);
    }

    public static List<Person> OrderList<T>(this List<Person> list, string attributeName, PersonAttribute defaultAttribute, Func<string, T> convertion)
    {
        return list.OrderBy(x => convertion((x.Attributes.FirstOrDefault(y => y.Name == attributeName) ?? defaultAttribute).Value)).ToList();

        // Query Syntax
        //return
        //    (from p in list
        //     let attribute = p.Attributes.FirstOrDefault(a => a.Name == attributeName) ?? defaultAttribute
        //     orderby attribute.Value
        //     select p).ToList();
    }
}

次に、この方法でリストを正しく並べ替えることができます。

List<Person> persons = ...
...
PersonAttribute defaultAttribute = new PersonAttribute() { Value = "0" };
var ordered = persons.OrderList("Age", defaultAttribute, x => Convert.ToInt32(x));

これにより、正しいソート順が得られます。属性が常に存在する場合は、削除できますdefaultAttribute

「名前」で並べ替えるには、次を使用します。

List<Person> persons = ...
...
PersonAttribute defaultAttribute = new PersonAttribute() { Value = String.Empty };
var ordered persons.OrderList("Name", defaultAttribute);
于 2010-04-23T08:13:43.130 に答える
0

1 つのアイテムに年齢属性がないという例外が発生していると思います。以下のコードを試してみましたが、うまくいきました - 他の投稿者が指摘したように、あなたのデータは少しずれていると思います。とにかく、以下はうまくいきます...

    List<Person> personList = new List<Person>();
    Random rand = new Random();

    //generate 50 random persons
    for (int i = 0; i < 50; i++)
    {
        Person p = new Person();
        p.Attributes = new List<PersonAttribute>();
        p.Attributes.Add(new PersonAttribute() { ID = 8, Name = "Age", Value = rand.Next(0, 100).ToString() });
        p.Attributes.Add(new PersonAttribute() { ID = 10, Name = "Name", Value = rand.Next(0, 100).ToString() });
        personList.Add(p);
    }

    var finalList = personList.OrderBy(c => c.Attributes.Find(a => a.Name == "Age").Value).ToList();
于 2009-03-30T04:01:59.220 に答える
0

構文が間違っている可能性がありますか?あなたのプロパティは Attributes と呼ばれていますが、コードで ObjectSettings と呼ばれるものを使用していますか? それともタイプミスですか。

その場合、すべての Person インスタンスに注文しようとしている Attribute がない限り、コードは正常に見えます。その場合、例外が発生します。

編集: また、Find を使用する代わりに、First を使用してみてください。

PersonList.OrderBy(p => p.Attributes.First(a => a.Name == "Age").Value)
于 2009-03-30T03:42:29.050 に答える