2009-03-30 5 views
13

내가 이런 구조를 주문 Linq를 사용에 문제가 연산 식 :정렬 목록 <T> 사용하여 쿼리

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를 사용하고 싶습니다 예를 들어 나이를 정렬하거나 이름을 정렬하는 등 내가 선택한 사람 특성에 따라 오름차순으로 사람 목록을 정렬하는 투영

나는

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

같은 것을 시도하고 그러나 구문은 나를 실패합니다. 모든 단서?

답변

5

목록 대신 키 - 값 사전을 사용하지 마십시오 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"]); 
+10

이 자신의 질문에 대답하지 않습니다

은 사용 '이름'을 정렬합니다. 그는 자신의 데이터를 재구성하는 방법을 묻지 않았고 아마도 (아마도 존재할 수 있고 아마도 변경 불가능한 레거시) 데이터 구조를 정렬하는 방법을 물었습니다. –

0

은 당신의 구문이 잘못되었다고 할 수 있을까요? 속성을 Attributes라고 부르지 만 코드에서 ObjectSettings라는 것을 사용하고 있습니까? 아니면 오타입니다.

그렇다면 모든 Person 인스턴스에 예외를 지정하려는 특성이있는 경우가 아니라면 코드가 정상적으로 보입니다.

EDIT : 또한 찾기를 사용하는 대신 첫 번째를 사용해보십시오.

PersonList.OrderBy(p => p.Attributes.First(a => a.Name == "Age").Value) 
+0

나는 오타를 수정했다. 내 문제가 IQueryable 및 List와 함께 Cast가 필요하다는 것을 알았다. 도와 줘서 고마워. –

0

한 항목에 연령 속성이없는 예외가 발생한다고 생각합니다. 아래의 코드를 시도해 보았습니다. 다른 포스터에서 지적한대로 데이터가 약간 떨어져 있다고 생각합니다. 어쨌든, 아래 작품은 괜찮아요 ...

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(); 
1

이 클래스는 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 
      ); 

나는 또한 각 키에 대해 하나 개의 값이 있다고 가정 - 그렇지 않으면 당신은 똑똑 코드가 필요 했어 ... ;-)

9

OrderBy은 새 시퀀스를 생성하는 LINQ 확장입니다. 나는 이것이 이전 게시물 알고

PersonList.Sort(p => p.Attributes.Find(
    s => s.Name == mySortAttribute).Value); 

public static class ListExtensions { 
    public static void Sort<TSource, TValue>(
    this List<TSource> source, 
    Func<TSource, TValue> selector) 
    { 
    var comparer = Comparer<TValue>.Default; 
    source.Sort((x, y) => comparer.Compare(selector(x), selector(y))); 
    } 
    public static void SortDescending<TSource, TValue>(
    this List<TSource> source, 
    Func<TSource, TValue> selector) 
    { 
    var comparer = Comparer<TValue>.Default; 
    source.Sort((x, y) => comparer.Compare(selector(y), selector(x))); 
    } 
} 
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을 참조하지 않고 라이브러리에 있기 때문에이 작업을 수행하지 않았습니다.

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);