【问题标题】:Order a list by id按 id 排序列表
【发布时间】:2019-11-14 17:44:19
【问题描述】:

我正在这个应用程序中使用 Jquery、c# 和 ASP.Net 制作一个 Web 应用程序,我插入 id 并使 id 如下所示: 前两位是当天,后两位是当月,第三两位是当年,最后一位是连续数字。

因此,如果我生成当天的第一个 id,则 id 将如下所示: DDMMYY+连续数字

我想根据 id 的日期和连续编号从最旧到最新排序所有 id

我怎样才能使用 linq 做到这一点?

【问题讨论】:

  • 你试过什么?什么具体不起作用?
  • @Rufus L,不完全是。日期的格式为 DDMMYY,这意味着您将按日、月、年和数字排序。大概需要的顺序实际上是年、月、日、数。我能想到的唯一方法是自定义比较器
  • @RossGurbutt 哦,对了!我一定有一个阅读障碍的时刻。谢谢。
  • id 列的数据类型是什么?
  • 保存“YYMMDD + CONSECUTIVE NUMBER”值的 id 属性的数据类型是什么?

标签: c# asp.net linq


【解决方案1】:

如果您不想将 id 的等效版本存储为强类型对象,我会编写一个如下所示的比较器(您可以根据您的确切要求对其进行调整,并在需要时添加验证)。

    public class IdComparer : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            int xYear = GetYear(x);
            int yYear = GetYear(y);
            if (xYear != yYear)
            {
                return xYear.CompareTo(yYear);
            }

            int xMonth = GetMonth(x);
            int yMonth = GetMonth(y);
            if (xMonth != yMonth)
            {
                return xMonth.CompareTo(yMonth);
            }

            int xDay = GetDay(x);
            int yDay = GetDay(y);
            if (xDay != yDay)
            {
                return xDay.CompareTo(yDay);
            }

            int xUniqueId = GetUniqueIdentifier(x);
            int yUniqueId = GetUniqueIdentifier(y);
            if (xUniqueId != yUniqueId)
            {
                return xUniqueId.CompareTo(yUniqueId);
            }

            return 0;
        }

        private static int GetYear(string id)
        {
            return Int32.Parse(id.Substring(4, 2));
        }

        private static int GetMonth(string id)
        {
            return Int32.Parse(id.Substring(2, 2));
        }

        private static int GetDay(string id)
        {
            return Int32.Parse(id.Substring(0, 2));
        }

        private static int GetUniqueIdentifier(string id)
        {
            return Int32.Parse(id.Substring(6));
        }
    }

然后你只需拨打idList.OrderBy(x =&gt; x, new IdComparer());

这感觉比试图在一个 linq 语句中完成所有事情更清晰、更容易阅读,除非您有这样做的特定要求?

然后可以对此类进行单元测试,并且任何问题/错误都比作为长 linq 语句的一部分更容易解决。

【讨论】:

    【解决方案2】:

    所以比较这些id的规则是:

    • 如果一个 id 的年份大于另一个,则认为该 id 更大。
    • 如果年份相等但一个 id 的月份大于另一个,则认为该 id 更大。
    • 如果年份和月份相同,但一个 id 的日期大于另一个,则认为该 id 更大。
    • 如果年、月、日相等,但一个 id 的递增部分大于另一个,则认为该 id 更大。

    所以现在我们只需要将 id 的值分成 4 个部分,然后我们就可以进行适当的比较了:

    • 年份部分,即Substring(4, 2)
    • 月份部分,即Substring(2, 2)
    • 白天部分,即Substring(0, 2)
    • 递增数字部分,即Substring(7)

    这是实现此目的的一种方法,即创建一个实现IComparer&lt;Item&gt; 的类(其中Item 是您的类)。注意:此答案假定您的 id 列是 string,因为您是通过将不同的值连接在一起来创建它的。如果它不是字符串,那么参数应该是int 值,并且需要先在方法内转换为字符串:

    public class ItemComparer : IComparer<Item>
    {
        public int Compare(Item x, Item y)
        {
            return Compare(x?.Id, y?.Id);
        }
    
        private int Compare(string first, string second)
        {
            // Rudimentary argument validation - this could be improved
    
            // Null check - consider null as less than non-null
            if (first == null) return second == null ? 0 : -1;
            if (second == null) return 1;
    
            // Number check - if fails, return string comparison
            if (!first.All(char.IsDigit) || !second.All(char.IsDigit))
                return first.CompareTo(second);
    
            // Length check - if fails, return int comparison
            if (first.Length < 7 || second.Length < 7)
                return int.Parse(first).CompareTo(int.Parse(second));
    
            // Compare years
            var result = int.Parse(first.Substring(4, 2))
                .CompareTo(int.Parse(second.Substring(4, 2)));
            if (result != 0) return result;
    
            // Compare months part
            result = int.Parse(first.Substring(2, 2))
                .CompareTo(int.Parse(second.Substring(2, 2)));
            if (result != 0) return result;
    
            // Compare days part
            result = int.Parse(first.Substring(0, 2))
                .CompareTo(int.Parse(second.Substring(0, 2)));
            if (result != 0) return result;
    
            // Compare incrementing number part
            return int.Parse(first.Substring(6)).CompareTo(int.Parse(second.Substring(6)));
        }
    }
    

    现在我们有了这个方法,我们可以通过id 订购一个项目列表。举个例子,让我们从一个简单的类开始:

    public class Item
    {
        public string Id { get; set; }
        public string Value { get; set; }
    }
    

    我们可以填充这些项目的列表并使用我们的比较器类对它们进行排序:

    public static void Main(string[] args)
    {
        var items = new List<Item>
        {
            // Second-most oldest item on Oct. 14, 2018
            new Item {Id = "14101801", Value = "Second"},
            // Fifth-most oldest item on Nov. 14, 2019
            new Item {Id = "14111901", Value = "Fifth"},
            // First-most oldest item on Oct. 13, 2018
            new Item {Id = "13101801", Value = "First"},
            // Fourth-most oldest item on Nov. 14, 2018 (id 02)
            new Item {Id = "14111802", Value = "Fourth"},
            // Third-most oldest item on Nov. 14, 2018 (id 01)
            new Item {Id = "14111801", Value = "Third"},
        };
    
        // Order our items by Id:
        items = items.OrderBy(i => i, new ItemComparer()).ToList();
    
        // Output our results
        items.ForEach(Console.WriteLine);
    
        GetKeyFromUser("\nDone! Press any key to exit...");
    }
    

    输出

    【讨论】:

      【解决方案3】:

      如果您将 ID 更改为 YYMMDD + 额外数字,LINQ 的 OrderBy(foo =&gt; foo.Id) 将完全按照您的需要工作。 YYMMDD 是自然有序的。

      如果您无法更改 ID 的格式,则需要实现一个比较器并将其提供给 OrderBy

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-03-10
        • 1970-01-01
        • 1970-01-01
        • 2019-02-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多