为数据类创建动态排序

时间:2014-07-28 19:51:22

标签: c# sorting

我正在尝试为我的基本数据类创建一个动态排序(只是一堆属性)。 以下代码演示了我要做的事情。它几乎可以工作。我唯一不明白的是为什么ThenBy似乎完全采用了这个列表。任何人都可以解释原因吗?

private void SortList(string[] sortCols)
{
    bool first = true;
    IOrderedEnumerable<Data> returnVal = null;

    Console.WriteLine("Sorting test data");

    if (sortCols.Length < 1)
        return;

    foreach (string col in sortCols)
    {

        if (first)
        {
            returnVal = _testData.OrderBy(p => typeof(Data).GetProperty(col).GetValue(p, null));
            //Or OrderByDescending
            first = false;
        }
        else
        {
            returnVal = returnVal.ThenBy(p => typeof(Data).GetProperty(col).GetValue(p, null));
            //Or ThenByDescending

        }

    }


    _testData = new List<Data>(returnVal);

}

_testData只是一个List Data类如下所示:

public class Data
{
    public string Name { get; set; }
    public int Age { get; set; }
    public double Income { get; set; }
    public bool Married { get; set; }

    public override string ToString()
    {
        return Name + "; age=" + Age.ToString() + "; income=" + Income.ToString() + "; married=" + Married.ToString();
    }
}

2 个答案:

答案 0 :(得分:2)

Unable to duplicate your problem。一切似乎排序正确:

public static void Main()
{
    var data1 = new Data() { Name = "Albert", Age = 99 };
    var data2 = new Data() { Name = "Zebra", Age = 1};
    var data3 = new Data() { Name = "Zebra", Age = 99};
    var data4 = new Data() { Name = "Albert", Age = 1 };

    _testData.Add(data1);
    _testData.Add(data2);
    _testData.Add(data3);
    _testData.Add(data4);

    SortList(new string[] { "Name", "Age" });

    foreach(var data in _testData)
    {
        Console.WriteLine(data.ToString());
    }

    Console.WriteLine(string.Empty);

    SortList(new string[] { "Age", "Name" });

    foreach(var data in _testData)
    {
        Console.WriteLine(data.ToString());
    }
}

结果:

  

对测试数据进行排序

     

阿尔伯特;年龄= 1;收入= 0;已婚=假

     

阿尔伯特;年龄= 99;收入= 0;已婚=假

     

斑马;年龄= 1;收入= 0;已婚=假

     

斑马;年龄= 99;收入= 0;已婚=假

     

     

对测试数据进行排序

     

阿尔伯特;年龄= 1;收入= 0;已婚=假

     

斑马;年龄= 1;收入= 0;已婚=假

     

阿尔伯特;年龄= 99;收入= 0;已婚=假

     

斑马;年龄= 99;收入= 0;已婚=假

更新(适用于.Net 4.0)

稍微更改代码可以解决问题(example):

private static void SortList(string[] sortCols)
{
    Console.WriteLine("Sorting test data");

    if (sortCols.Length < 1)
        return;

    IOrderedEnumerable<Data> returnVal = _testData.OrderBy(p => typeof(Data).GetProperty(sortCols[0]).GetValue(p, null));

    foreach (string col in sortCols.Skip(1))
    {
        returnVal = returnVal.ThenBy(p => typeof(Data).GetProperty(col).GetValue(p, null));
        //Or ThenByDescending
    }

    _testData = returnVal.ToList();
}

答案 1 :(得分:1)

你最好创建一个明确对每个属性进行比较的IComparer(因此你可以在其上有一个指定属性顺序的公共属性)。然后你可以只排序一次。

像这样的东西

public class DataComparer : Comparer<Data>
{
    private readonly IList<string> _sortedProperties;

    public DataComparer(IEnumerable<string> sortedProperties)
    {
        _sortedProperties = new List<string>(sortedProperties);
    }

    public override int Compare(Data x, Data y)
    {
        int result = 0;
        foreach (var property in _sortedProperties)
        {
            if (property == "Name")
            {
                result = String.Compare(x.Name, y.Name, StringComparison.Ordinal);
            }
            else if (property == "Age")
            {
                result = x.Age.CompareTo(y.Age);
            }

            // Do other comparisons here

            if (result != 0)
                return result;
        }

        return 0;
    }
}

此实现将使用给定的属性集合创建DataComparer,这些属性充当需要比较的属性。然后,Compare()将以所需的排序顺序遍历属性,直到找到不匹配的比较并返回。

最终结果将是更快的排序操作,输出类似

的内容
// "Jim Frost" 13
// "Jim Frost" 24
// "Jim Smith" 11

我们首先要对Name属性进行排序,然后是Age等。

修改

你可以这样排序,

_testData.Sort(new DataComparer(sortCols));