c# - 根据一个可以保存多个值的变量对数组进行排序

标签 c# arrays linq sorting

如何对 Accounts 的数组进行排序需要在 PersonRoles 的数组上排序那说明关联人在该帐户中扮演什么角色?

例如,

Bob 是帐户 O 的所有者 ( 12) , 帐户 CO 的联合签名者 ( 123 ) , 和账户的受益人 1234 .

Joe 是帐户 O 的所有者 ( 123)和帐号1234账户 BE 的受益人 ( 12 ) .

我将如何对 Accounts 的数组进行排序? for Bob 按照所有者 ( O ) 首先,然后是联合签名者 ('CO'),然后是受益人 ( BE ) 的顺序。

账户对象结构

Accounts
{
    AccountNumber: 12,
    PersonRoles: [
                     {
                         AccountRoleCode: "O",
                         AccountRoleDescription: "Owner",
                         Person: "Bob"
                     },
                     {
                         AccountRoleCode: "CO",
                         AccountRoleDescription: "Co-Signer",
                         Person: ""
                     },
                     {
                         AccountRoleCode: "BE",
                         AccountRoleDescription: "Beneficiary",
                         Person: "Joe"
                     },
                 ],
    Balance: 5.00
},
{
    AccountNumber: 123,
    PersonRoles: [
                     {
                         AccountRoleCode: "O",
                         AccountRoleDescription: "Owner",
                         Person: "Joe"
                     },
                     {
                         AccountRoleCode: "CO",
                         AccountRoleDescription: "Co-Signer",
                         Person: "Bob"
                     },
                     {
                         AccountRoleCode: "BE",
                         AccountRoleDescription: "Beneficiary",
                         Person: null
                     },
                 ],
    Balance: 100.00
},
{
    AccountNumber: 1234,
    PersonRoles: [
                     {
                         AccountRoleCode: "O",
                         AccountRoleDescription: "Owner",
                         Person: "Joe"
                     },
                     {
                         AccountRoleCode: "CO",
                         AccountRoleDescription: "Co-Signer",
                         Person: null
                     },
                     {
                         AccountRoleCode: "BE",
                         AccountRoleDescription: "Beneficiary",
                         Person: "Bob"
                     },
                 ],
    Balance: 10000000.00
}

从 API 返回的 Bob 下列出的原始帐户数组。

[1234, 12, 123]

所需的排序数组。

[12, 123, 1234]

我最初的方法是在数组上使用 LINQ,但我不确定如何遍历 Accounts[]然后循环遍历 PersonRoles[]Accounts[] 进行排序基于 PersonRoles[] .

这是否需要双 LINQ 查询?或者另一种方法会更好吗?

最佳答案

public class AccountsByNameComparer : IComparer<Account>
{
    private readonly string _name;

    public AccountsByNameComparer(string name)
    {
        _name = name;
    }

    public int Compare(Account x, Account y)
    {
        return AccountSortValue(x).CompareTo(AccountSortValue(y));
    }

    private int AccountSortValue(Account account)
    {
        if (account.PersonRoles.Any(role => role.AccountRoleCode == "O"
                                            && role.Name == _name)) return 0;
        if (account.PersonRoles.Any(role => role.AccountRoleCode == "CO"
                                            && role.Name == _name)) return 1;
        if (account.PersonRoles.Any(role => role.AccountRoleCode == "BE"
                                            && role.Name == _name)) return 2;
        return 3;
    }
}

现在你可以做

accounts.Sort(new AccountsByNameComparer("Bob"));

var sorted = accounts.OrderBy(a => a, new AccountsByNameComparer("Bob"));

这样做的好处是

  • 您可以对比较器进行单元测试
  • 你可以对同一个类使用不同的比较器,以防在其他情况下你想进行不同的排序
  • 将它放在一个单独的类中可确保您在发现自己需要在多个地方进行相同排序时不会重复代码。

这是一个令人遗憾的漫长而复杂的单元测试。但是您必须验证它是否以某种方式工作,这通常比实际运行整个应用程序更容易。

[TestClass]
public class SortAccountsByNameTests
{
    [TestMethod]
    public void AccountsAreSortedInCorrectOrder()
    {
        var account1 = new Account
        {
            PersonRoles = new PersonRole[]
            {
                new PersonRole {AccountRoleCode = "BE", Name = "Bob"},
                new PersonRole {AccountRoleCode = "CO", Name = "Steve"},
                new PersonRole {AccountRoleCode = "O", Name = "John"},
            }
        };
        var account2 = new Account
        {
            PersonRoles = new PersonRole[]
            {
                new PersonRole {AccountRoleCode = "CO", Name = "Bob"},
                new PersonRole {AccountRoleCode = "O", Name = "Steve"},
                new PersonRole {AccountRoleCode = "BE", Name = "John"},
            }
        };
        var account3 = new Account
        {
            PersonRoles = new PersonRole[]
            {
                new PersonRole {AccountRoleCode = "O", Name = "Bob"},
                new PersonRole {AccountRoleCode = "CO", Name = "Steve"},
                new PersonRole {AccountRoleCode = "BE", Name = "John"},
            }
        };
        var account4 = new Account
        {
            PersonRoles = new PersonRole[]
            {
                new PersonRole {AccountRoleCode = "O", Name = "Al"},
                new PersonRole {AccountRoleCode = "CO", Name = "Steve"},
                new PersonRole {AccountRoleCode = "BE", Name = "John"},
            }
        };
        var unsorted = new Account[] {account1, account2, account3, account4};
        var comparer = new AccountsByNameComparer("Bob");
        var sorted = unsorted.OrderBy(a => a, comparer);
        var expectedOrder = new Account[]{account3, account2, account1, account4};
        Assert.IsTrue(expectedOrder.SequenceEqual(sorted));
    }
}

我现在要得意忘形了。如果您想更改排序顺序而不重写整个比较器怎么办?或者您只是不喜欢那些 if 语句? (抱歉,这很讨厌而且没用。我为什么要这样做?)

public class AccountsByNameComparer : IComparer<Account>
{
    private readonly string _name;
    private readonly List<string> _preferredRoleSequence;

    public AccountsByNameComparer(string name, IEnumerable<string> preferredRoleSequence)
    {
        _name = name;
        _preferredRoleSequence = preferredRoleSequence.ToList();
    }

    public int Compare(Account x, Account y)
    {
        return AccountSortValue(x).CompareTo(AccountSortValue(y));
    }

    private int AccountSortValue(Account account)
    {
        var rolesMatchedByName = account.PersonRoles
            .Where(role => role.Name == _name);
        var preferredRoleMatches =
            rolesMatchedByName.Select(role => 
                _preferredRoleSequence.IndexOf(role.AccountRoleCode))
                    .Where(index => index > -1)
                    .ToArray();
        if (preferredRoleMatches.Any())
            return preferredRoleMatches.Min();
        return Int32.MaxValue;
    }
}

public class ExecutiveAccountsByNameComparer : AccountsByNameComparer
{
   public ExecutiveAccountsByNameComparer(string name)
        :base(name, new []{"O", "CO", "BE" }) { }

}

关于c# - 根据一个可以保存多个值的变量对数组进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47895661/

相关文章:

php - 比较 php 数组的结构而不考虑内容

javascript - 将数组的引用存储在数组中

vb.net - 如何使用 LINQ 选择最新且不同的记录?

c# - 使用 LINQ 求字段总和

c# - Visual Studio 显示了很多错误,但只有一个实际错误

c# - 为什么存在这种令人困惑的语法?

c# - 继续在 dotnet highchart 上画线

c# - 如何将滚动条添加到网格

c - 确定 3d 数组中行元素的差异

C# LINQ - 找不到 IListSource [Xamarin Forms]