使用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投影来对按我选择的person属性提升的人员列表进行排序,例如,对Age进行排序,或者对FirstName进行排序。
我正在尝试像
这样的东西string mySortAttribute = "Age"
PersonList.OrderBy(p => p.PersonAttribute.Find(s => s.Name == mySortAttribute).Value);
但语法失败了。有线索吗?
答案 0 :(得分: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)));
}
}
答案 1 :(得分: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。
答案 2 :(得分:5)
为什么不使用键值字典而不是List&lt; PersonAttribute&gt; ?我认为它会更适合,并使其他一切变得更容易。
更新 - 像这样:
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"]);
答案 3 :(得分: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
);
我还假设每个键都有一个值 - 否则你需要更聪明的代码......; - )
答案 4 :(得分:0)
可能是你的语法错了吗?您的属性称为属性,但您在代码中使用了名为ObjectSettings的东西?或者这是一个错字。
如果是,那么您的代码看起来很好,除非并非所有Person实例都具有您尝试订购的属性,在这种情况下您将获得异常。
编辑: 此外,请尝试使用First。
,而不是使用FindPersonList.OrderBy(p => p.Attributes.First(a => a.Name == "Age").Value)
答案 5 :(得分: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();
答案 6 :(得分:0)
有些情况需要考虑:
如果您创建此扩展方法类:
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);