C# DataView.Sort - 不仅仅是 asc/desc(需要自定义排序)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/582374/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 09:09:32  来源:igfitidea点击:

DataView.Sort - more than just asc/desc (need custom sort)

c#asp.net

提问by bugfixr

I've got a report being built from a dataset. The dataset uses the Sort property to order the data. I know that I can create a sort expression like this:

我有一个从数据集构建的报告。数据集使用 Sort 属性对数据进行排序。我知道我可以创建这样的排序表达式:

"field desc, field2 asc"

“field desc,field2 asc”

But what I need now is a way to do a custom sort. In SQL, I can perform a custom sort by doing something like this:

但我现在需要的是一种进行自定义排序的方法。在 SQL 中,我可以通过执行以下操作来执行自定义排序:

order by 
    case when field = 'Some Value' then 0 end
    case when field = 'Another Value' then 1 end

To basically re-define my sort (i.e, Some Value comes before Another Value).

基本上重新定义我的排序(即,某个值在另一个值之前)。

Is it possible to do something similar as a sort expression against a DataView?

是否可以对 DataView 执行类似于排序表达式的操作?

采纳答案by BFree

Ok, I just whipped this up real quick, and didn't do all the neccessary error handling and null checking, but it should give you an idea and should be enough to get you started:

好的,我只是快速完成了这个,并没有做所有必要的错误处理和空值检查,但它应该给你一个想法,应该足以让你开始:

public static class DataTableExtensions
{
    public static DataView ApplySort(this DataTable table, Comparison<DataRow> comparison)
    {

        DataTable clone = table.Clone();
        List<DataRow> rows = new List<DataRow>();
        foreach (DataRow row in table.Rows)
        {
            rows.Add(row);    
        }

        rows.Sort(comparison);

        foreach (DataRow row in rows)
        {
            clone.Rows.Add(row.ItemArray);
        }

        return clone.DefaultView;
    }


}

Usage:

用法:

    DataTable table = new DataTable();
    table.Columns.Add("IntValue", typeof(int));
    table.Columns.Add("StringValue");

    table.Rows.Add(11, "Eleven");
    table.Rows.Add(14, "Fourteen");
    table.Rows.Add(10, "Ten");
    table.Rows.Add(12, "Twelve");
    table.Rows.Add(13, "Thirteen");

//Sort by StringValue:

//按字符串值排序:

 DataView sorted = table.ApplySort((r, r2) =>
        {
            return ((string)r["StringValue"]).CompareTo(((string)r2["StringValue"]));
        });

Result:

结果:

11 Eleven

11 十一

14 Fourteen

14 十四

10 Ten

10 十

13 Thirteen

13 十三

12 Twelve

12 十二

//Sort by IntValue:

//按整数排序:

DataView sorted = table.ApplySort((r, r2) =>
            {
                return ((int)r["IntValue"]).CompareTo(((int)r2["IntValue"]));
            });

Result:

结果:

10 Ten

10 十

11 Eleven

11 十一

13 Thirteen

13 十三

12 Twelve

12 十二

14 Fourteen

14 十四

EDIT: Changed it to extension method.

编辑:将其更改为扩展方法。

Now in your Lambda, (or you can create a full blown Comparison method) you can do any kind of custom sorting logic that you need. Remember, -1 is less than, 0 is equal to, and 1 is greater than.

现在在您的 Lambda 中(或者您可以创建一个完整的比较方法),您可以执行所需的任何类型的自定义排序逻辑。请记住,-1 小于,0 等于,1 大于。

回答by user53794

I don't think so. You could however change you SQL to return a "CustomSort" column that is the result of your case statement:

我不这么认为。但是,您可以更改 SQL 以返回作为 case 语句结果的“CustomSort”列:

select
    (case when f = 'a' then 0 else 1 end) as CustomSort
from MyTable

回答by REA_ANDREW

You could use an if or a switch statement to get similar functionality to the select case statement:

您可以使用 if 或 switch 语句来获得与 select case 语句类似的功能:

            if (Something == "1")
                MyView.Sort = "Field1 ASC";
            else
                MyView.Sort = "Field2 ASC";

OR

或者

            switch (MyProperty)
            {
                case 1:
                    MyView.Sort = "Field1 ASC";
                    break;
                case 2:
                    MyView.Sort = "Field2 ASC";
                    break;
                default:
                    MyView.Sort = "Field3 ASC";
                    break;
            }

回答by Robert Rossney

I like BFree's answer, though I'd worry about the risk that my code would end up updating the cloned table rather than the real one. (I haven't thought through it enough to know if that's actually an issue if you're only using the extension method in a DataView.)

我喜欢 BFree 的回答,尽管我担心我的代码最终会更新克隆表而不是真实表的风险。(我还没有仔细考虑过,如果您只在DataView.

You can do this on the original DataTableby adding a calculated DataColumnto it (using the Expressionproperty) and then sorting on its value.

您可以DataTable通过向原始数据添加一个计算值DataColumn(使用该Expression属性)然后对其值进行排序来对原始数据执行此操作。

In your case it would be something like:

在你的情况下,它会是这样的:

DataColumn c = myTable.Columns.Add("Sort", typeof(int));
c.Expression = "iif(field='SomeValue', 0, iif(field='AnotherValue', 1, 2))";

which sorts SomeValuefirst, AnotherValuesecond, and everything else after that.

排序SomeValue第一,AnotherValue第二,以及之后的所有其他内容。

回答by Stuart

I know this post is a bit older, but I went about this slightly different by implementing IComparable. In this example, I wanted to sort by version (which is in the format 0.0.0.0 as a string).

我知道这篇文章有点旧,但我通过实现 IComparable 来解决这个问题。在这个例子中,我想按版本排序(格式为 0.0.0.0 作为字符串)。

Here is the Versioning class which implements IComparable:

这是实现 IComparable 的 Versioning 类:

public class Versioning : IComparable {
    string _version;

    int _major;
    public int Major { 
        get { return (_major); } 
        set { _major = value; } 
    }

    int _minor;
    public int Minor {
        get { return (_minor); }
        set { _minor = value; }
    }

    int _beta;
    public int Beta {
        get { return (_beta); }
        set { _beta = value; }
    }

    int _alpha;
    public int Alpha {
        get { return (_alpha); }
        set { _alpha = value; }
    }

    public Versioning(string version) {
        _version = version;

        var splitVersion = SplitVersion();
        if (splitVersion.Length < 4) {
            Major = Minor = Beta = Alpha = 0;
        }

        if (!int.TryParse(splitVersion[0], out _major)) _major = 0;
        if (!int.TryParse(splitVersion[1], out _minor)) _minor = 0;
        if (!int.TryParse(splitVersion[2], out _beta)) _beta = 0;
        if (!int.TryParse(splitVersion[3], out _alpha)) _alpha = 0;
    }

    string[] SplitVersion() {
        return (_version.Split('.'));
    }

    int GetCompareTo(Versioning versioning) {
        var greater = -1;
        var equal = 0;
        var less = 1;

        if (Major > versioning.Major) return (greater);
        if (Major < versioning.Major) return (less);
        if (Minor > versioning.Minor) return (greater);
        if (Minor < versioning.Minor) return (less);
        if (Beta > versioning.Beta) return (greater);
        if (Beta < versioning.Beta) return (less);
        if (Alpha > versioning.Alpha) return (greater);
        if (Alpha < versioning.Alpha) return (less);

        return (equal);
    }

    public int CompareTo(Versioning versioning) {
        return (GetCompareTo(versioning));
    }

    public override string ToString() {
        return (_version);
    }

    public int CompareTo(object obj) {
        if (obj == null) return (1);
        return (GetCompareTo((Versioning)obj));
    }
}

And when you add the column to the table, instead of adding Version as a string, you add it as the Versioning class:

当您将列添加到表中时,不是将 Version 作为字符串添加,而是将其添加为 Versioning 类:

_table.Columns.Add("Version", typeof(Versioning));
_view = new View(_table);

And then sort normally:

然后正常排序:

_view.Sort = "Version";