如何按前两个字符然后按字母对列表中的对象属性进行排序



我有一个对象列表。对象是保险单。好吧,每个保单编号的第一部分都是字母字符,然后是所有数字。我需要对列表中以 CA 开头的策略编号的所有策略进行排序,然后按字母数字排序。例如,如果我有三个策略,AB10001,CA20001,CA20003,则顺序应该首先都是"CA",然后按如下所示排序:enter code here

CA20001
CA20003
AB10001

根据我对常规排序的理解,让我失望的是如何首先获得所有 CA,因为它们不适用于 alpha 顺序。 我认为可能,将所有以CA为前缀的策略名称拉到一个新列表中,然后按数字排序。然后在第二个列表中对剩菜进行排序。然后将第二个列表附加到"CA"排序列表中(如果有意义)。尽管使用 lambda,但必须有一种更清洁的方法。

你可以用类似的东西来实现这一点。

var list = new List<string> { "AB10001", "CA20003", "CA20001" };
var ordered = list.OrderByDescending(s => s.StartsWith("CA")).ThenBy(s => s);
foreach(var o in ordered) Console.WriteLine(o);

哪些输出

CA20001

CA20003

AB10001

基本上,您首先根据是否以"CA"开头然后按实际字符串值对所有内容进行排序。 您必须使用降序,因为false被认为小于 true

您可以尝试以下操作:

const string CAHeader = "CA";
IEnumerable<string> sorted = 
  list.OrderBy(s => s.StartsWith(CAHeader) ? s.Substring(CAHeader.Length) : s);

实现 IComparer 并将自定义逻辑放入 Compare 中。

这是一个IComparer实现。它比 juharr 的解决方案多出大约 1200% 的代码行数。但是在我还没有想到的某些情况下,它可能很方便。

比较器:

public class PolicyComparer : IComparer<Policy>
{
    public static PolicyComparer Instance { get; } = new PolicyComparer();
    public int Compare(Policy x, Policy y)
    {
        return x.PolicyNumber.StartsWith("CA") ^ y.PolicyNumber.StartsWith("CA") 
            ? (x.PolicyNumber.StartsWith("CA") ? -1 : 1)
            : string.Compare(x.PolicyNumber, y.PolicyNumber, StringComparison.Ordinal);
    }
}

排序扩展:

public static class PolicyExtensions
{
    public static IEnumerable<Policy> Sort(this IEnumerable<Policy> unsortedPolicies)
    {
        var sorted = new List<Policy>(unsortedPolicies);
        sorted.Sort(PolicyComparer.Instance);
        return sorted;
    }
}

我用于测试的Policy类:

public class Policy
{
    public string PolicyNumber { get; set; }
}

单元测试:

    [TestMethod]
    public void PoliciesAreSortedByCAfirst()
    {
        var unsorted = new Policy[]
        {
            new Policy {PolicyNumber = "AB10001"},
            new Policy {PolicyNumber = "CA20003"},
            new Policy {PolicyNumber = "CA20001"}
        };
        var sorted = unsorted.Sort();
        var expectedOrder = new string[] {"CA20001", "CA20003", "AB10001"};
        Assert.IsTrue(expectedOrder.SequenceEqual(sorted.Select(policy=>policy.PolicyNumber)));
    }

我看错了。需要排序的不是策略。这是保单号码。实际上,将策略编号声明为单独的类而不是使用字符串并不是一个坏主意。原因是您可以"隐藏"其实现。也许在某个时候,策略"数字"变成了两个字段的组合。

这更有意义,因为策略编号有自己的逻辑,与Policy无关。它具有自定义排序顺序。它可能有自己的验证规则。如果它只是连接到Policy的字符串,那么Policy必须拥有所有这些。您可能希望将保单编号放在本身不是保单的东西上,例如对保单的索赔,这并非不现实。(这种 ID 可能随处可见。

从这个角度来看,这是一个解决方案:

public class PolicyNumber : IComparable
{
    private readonly string _number;
    public PolicyNumber(string number)
    {
        _number = number;
    }
    public int CompareTo(object obj)
    {
        var other = obj as PolicyNumber;
        if (other == null) return 0;
        return _number.StartsWith("CA") ^ other._number.StartsWith("CA")
            ? (_number.StartsWith("CA") ? -1 : 1)
            : string.Compare(_number, other._number, StringComparison.Ordinal);
    }
    public override string ToString()
    {
        return _number;
    }
    public override bool Equals(object obj)
    {
        var other = obj as PolicyNumber;
        return other != null && string.Equals(_number, other._number);
    }
    protected bool Equals(PolicyNumber other)
    {
        return string.Equals(_number, other._number);
    }
    public override int GetHashCode()
    {
        return (_number != null ? _number.GetHashCode() : 0);
    }
}

和单元测试:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void PoliciesAreSortedByCAfirst()
    {
        var unsorted = new Policy[]
        {
            new Policy{Number = new PolicyNumber("AB10001")},
            new Policy{Number = new PolicyNumber("CA20003")},
            new Policy{Number = new PolicyNumber("CA20001")}
        };
        var sorted = unsorted.OrderBy(policy => policy.Number);
        var expectedOrder = new Policy[]
        {
            unsorted[2], unsorted[1], unsorted[0]
        };
        Assert.IsTrue(expectedOrder.SequenceEqual(sorted));
    }
}

请注意,这如何允许PolicyNumber"拥有"自己的逻辑。使用它的类只是对它进行排序,而不知道或不关心它是如何排序的。你仍然可以像一根绳子一样比较它的相等性。

单元测试显示了它的易用性。与其要求一些东西为你分类,不如对它进行排序。如果是带有策略编号的Policy,则可以按策略编号或其他内容对其进行排序。

最新更新