【问题标题】:Custom OrderBy on a List based on a string property value基于字符串属性值的 List 上的自定义 OrderBy
【发布时间】:2018-05-27 08:43:09
【问题描述】:

我有以下课程:

public class Document
{
    public string DocumentSection { get; set; }
    public string DocumentName { get; set; }
}

我想根据 DocumentSection 属性订购以下列表:

List<Document> documents = new List<Document>();
        documents.Add(new Document { DocumentSection = "Section One", DocumentName = "doc1" });
        documents.Add(new Document { DocumentSection = "Section Two", DocumentName = "doc1123" });
        documents.Add(new Document { DocumentSection = "Section Three", DocumentName = "doc113" });
        documents.Add(new Document { DocumentSection = "Section Four", DocumentName = "doc123" });
        documents.Add(new Document { DocumentSection = "Section Five", DocumentName = "doc11" });

理论上我知道我应该实现 IComparer 来获得它,但这就是困难所在,我不太确定如何在一般水平上实现它......实现这一目标的最佳解决方案是什么订购?

【问题讨论】:

  • DocumentSection 总是带有第一节,第二节,...等,然后一种方法是将一,二...(修剪节字符串)更改为数字和命令。另一个解决方案是,不是将文档部分作为字符串,而是将其作为数值并对其进行排序。如果需要该属性在绑定视图上显示文本,则编写一个转换器将数值更改为文本(带有所需的前后修复字符串。)
  • 是的,总是这样......问题是我根本无法更改模型结构
  • “第一节”、“第二节”、“第三节”……等等……“一百节”……很糟糕……但我必须处理现在这个真实的案例场景......一个大的 switch 语句将完成这项工作......或 Dictionary {"One", 1"} {"Two", 2 "} 等......但我有手写所有这些情况......如果有更好的选择,我很好奇
  • 如果部分是 1001,DocumentSection具体 值是多少?如果是 10914 呢?
  • @RaduOlteanu 检查我的代码,这是 支持所有数字 ....,-2,-1,0,1,2,3,.... 并且不需要在单词中写入任何数字...。检查一下,我确定这对你有好处。

标签: c# .net algorithm linq


【解决方案1】:

试试这个:

var orderedList = documents.OrderBy(r => GetOrder(r.DocumentSection));

GetOrder() 方法是:

Public Static int GetOrder(string _arg)
{
    switch (_arg)
    {
        case 'Section One':
            return 1;
        case 'Section Two':
            return 2;
        case 'Section Three':
            return 3;
            .
            .
            .
        default:
            return int.MaxValue;
    }
}

【讨论】:

  • @RaduOlteanu 我认为这个最明显的解决方案是最清晰的一个
  • 这甚至无法编译。大小写错误,参数与 switch 参数不匹配。
  • switch的参数打错了,但是很明显但是我编辑了它
【解决方案2】:

最简单的方法是使用 Linq:

List<Order> SortedList = objListOrder.OrderBy(o=>o.Order).ToList();

示例:

List<Document> SortedList = documents.OrderBy(o=>o.DocumentName).ToList();

长答案 您需要自定义上述订购方式,但您不需要在此代码中输入所有数字

使用wordify 方法,您可以将数字转换为单词

使用normalize_number 方法,我们将result wordfirst word 都标准化,这样我们就可以检查结果词和第一个词

我们有一个循环,我们不喜欢总是创建单词,所以我们可以使用 Dictionary 并检查数字,我们在 get_wordify 方法中执行此操作。

现在SetOrder我们可以找到正确的顺序

所以只需使用此代码:

    private int current_order = 0;
    private int SetOrder(string _arg)
    {

        string number = _arg.ToLower()
            .Replace("section", "")
            .TrimStart(' ')
            .TrimEnd(' ');
        number = normalize_number(number);

        for (int i = 0;
            //you can limit loop here (i<99999) or not !
            ; i++)
        {
            string wordify_number = get_wordify(i);

            if (wordify_number == number)
            {
                //if all number is available return i+1
                //return i + 1;

                //otherwise
                current_order++;
                return current_order;
            }

        }

    }
    private string normalize_number(string number)
    {
        number = number.Replace("-", " ")
                        .Replace("_", " ")
                        .Replace(",", " ");

        //also you can replace "and" if you want 

        //.Replace("  ", " "); 
        //regex is better for find and replace multi space

        RegexOptions options = RegexOptions.None;
        Regex regex = new Regex("[ ]{2,}", options);
        number = regex.Replace(number, " ");


        return number;
    }

    Dictionary<int, string> Numbers_dic = new Dictionary<int, string>();
    private string get_wordify(int i)
    {
        string wordify_number = "";
        if (Numbers_dic.ContainsKey(i))
        {
            wordify_number = Numbers_dic[i];
        }
        else {
            wordify_number = wordify(i);
            wordify_number = normalize_number(wordify_number);

            Numbers_dic.Add(i, wordify_number);
        }

        return wordify_number;
    }
    private string wordify(decimal number)
    {
        if (number == 0) return "zero";
        var units = " one two three four five six seven eight nine".Split();
        var teens = " eleven twelve thir# four# fif# six# seven# eigh# nine#".Replace("#", "teen").Split();
        var tens = " ten twenty thirty forty fifty sixty seventy eighty ninety".Split();
        var thou = " thousand m# b# tr# quadr# quint# sext# sept# oct#".Replace("#", "illion").Split();
        var minus_str = (number < 0) ? "minus " : "";
        var res_number = "";
        var p = 0;
        number = Math.Abs(number);
        while (number > 0)
        {
            int b = (int)(number % 1000);
            if (b > 0)
            {
                var h = (b / 100);
                var t = (b - h * 100) / 10;
                var u = (b - h * 100 - t * 10);

                var str = ((h > 0) ? units[h] + " hundred" + ((t > 0 | u > 0) ? " and " : "") : "")
                      + ((t > 0) ? (t == 1 && u > 0) ? teens[u] : tens[t] + ((u > 0) ? "-" : "") : "")
                      + ((t != 1) ? units[u] : "");
                str = (((number > 1000) && (h == 0) && (p == 0)) ? " and " : (number > 1000) ? ", " : "") + str;

                res_number = str + " " + thou[p] + res_number;
            }

            number = number / 1000;

            if (number < 1)
            {
                break;
            }

            p++;
        }
        return minus_str + res_number;
    }

用法:

private void Do_order()
{
    var orderedList = documents.OrderBy(r => SetOrder(r.DocumentSection));
}

【讨论】:

  • OP 希望按DocumentSection 排序。此代码将按字母顺序排列项目(“五”和“四”将在“一”之前)。
  • 是的,已编辑,现在比第一个接受的答案更好!
猜你喜欢
  • 2011-07-13
  • 1970-01-01
  • 2015-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-22
  • 1970-01-01
  • 2017-08-13
相关资源
最近更新 更多