C# 对一个可以容纳多个值的变量进行排序

C# 对一个可以容纳多个值的变量进行排序,c#,arrays,linq,sorting,C#,Arrays,Linq,Sorting,如何对需要排序的帐户数组进行排序,该数组的PersonRoles表示关联人员在该帐户中的角色 比如说, Bob是账户12的所有者(O),账户123的共同签署人(Co),以及账户1234的受益人 乔是账户123的所有者(O),账户1234是账户12的受益人(BE) 我将如何首先按照所有者(O)的顺序对Bob的账户数组进行排序,然后按照该顺序对共同签署人()和受益人(BE)进行排序 帐户对象结构 Accounts { AccountNumber: 12, PersonRoles: [

如何对需要排序的
帐户数组
进行排序,该数组的
PersonRoles
表示关联人员在该帐户中的角色

比如说,

Bob是账户
12
的所有者(
O
),账户
123
的共同签署人(
Co
),以及账户
1234
的受益人

乔是账户
123
的所有者(
O
),账户
1234
是账户
12
的受益人(
BE

我将如何首先按照所有者(
O
)的顺序对Bob的
账户数组进行排序,然后按照该顺序对共同签署人(
)和受益人(
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]

所需的排序数组

[121231234]

我最初的方法是在阵列上使用LINQ,但我不确定如何循环通过
帐户[]
,然后循环通过
个人角色[]
,根据
个人角色[]
帐户[]
进行排序


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

类似的方法应该可以:

    var result = accounts
        .Select(a => new
        {
            a.AccountNumber,
            RoleCodes = a.PersonRoles
                .Where(r => r.Person == "Bob")
                .Select(r => r.AccountRoleCode)
                .ToArray(),
        })
        .OrderBy(a => a.RoleCodes.Select(code => GetOrderByCode(code)).Max())
        .ThenBy(a => a.AccountNumber);

像这样的方法应该会奏效:

    var result = accounts
        .Select(a => new
        {
            a.AccountNumber,
            RoleCodes = a.PersonRoles
                .Where(r => r.Person == "Bob")
                .Select(r => r.AccountRoleCode)
                .ToArray(),
        })
        .OrderBy(a => a.RoleCodes.Select(code => GetOrderByCode(code)).Max())
        .ThenBy(a => a.AccountNumber);

这里有一种方法,假设Bob在所有帐户中只有一个角色:

var ordered = 
    from a in Accounts
    from r in a.PersonRoles 
    where r.Person == "Bob" 
    let ordering = r.AccountRoleCode == "O" ? 1 : r.AccountRoleCode == "CO" ? 2 : 3
    orderby ordering
    select a.AccountNumber;
变量,如果Bob可以有多个角色(并且Bob在每个帐户中都有一个角色)。在这种情况下,我们首先选择正确的角色,按照指定的顺序选择第一个角色:

var ordered = 
    from a in Accounts
    let bobsrole = (
        from r in a.PersonRoles
        where r.Person == "Bob"
        let o = r.AccountRoleCode == "O" ? 1 : r.AccountRoleCode == "CO" ? 2 : 3
        orderby o
        select (rolename: r,ordering: o)
    ).First()
    orderby bobsrole.ordering
    select a.AccountNumber;

读者练习:如果有Bob不参与的账户怎么办?

这里有一种方法,假设Bob在所有账户中都只有一个角色:

var ordered = 
    from a in Accounts
    from r in a.PersonRoles 
    where r.Person == "Bob" 
    let ordering = r.AccountRoleCode == "O" ? 1 : r.AccountRoleCode == "CO" ? 2 : 3
    orderby ordering
    select a.AccountNumber;
变量,如果Bob可以有多个角色(并且Bob在每个帐户中都有一个角色)。在这种情况下,我们首先选择正确的角色,按照指定的顺序选择第一个角色:

var ordered = 
    from a in Accounts
    let bobsrole = (
        from r in a.PersonRoles
        where r.Person == "Bob"
        let o = r.AccountRoleCode == "O" ? 1 : r.AccountRoleCode == "CO" ? 2 : 3
        orderby o
        select (rolename: r,ordering: o)
    ).First()
    orderby bobsrole.ordering
    select a.AccountNumber;

读者练习:如果有不涉及Bob的账户怎么办?

您可以使用如下Linq语句:

var givenPerson = "Bob";
Accounts.Where(a => a.PersonRoles.SelectMany(r => r.Person).Contains(givenPerson))
    .OrderBy(a => a, new CustomComparerForRoleCode(givenPerson));
要按
AccountRoleCode
进行自定义比较排序,您需要一个比较器类:

public class CustomComparerForRoleCode : IComparer<PersonRole[]>
{
    public string PersonInRole { get; set; }

    public CustomComparerForRoleCode(string personInRole) {
        this.PersonInRole = personInRole;
    }

    public int Compare(PersonRole[] x, PersonRole[] y) {
        var roleCode = x.First(r => r.Person == PersonInRole).AccountRoleCode;
        var otherRoleCode = y.First(r => r.Person == PersonInRole).AccountRoleCode;
        if (roleCode == otherRoleCode)
            return 0;
        switch (roleCode) {
            case "O":
                return 1;
            case "BE":
                return -1;
            case "CO":
                if (otherRoleCode == "O")
                    return -1;
                return 1;
        }
    }
}
公共类CustomComparerForRoleCode:IComparer
{
公共字符串PersonInRole{get;set;}
公共CustomComparerForRoleCode(字符串personInRole){
this.PersonInRole=PersonInRole;
}
公共整数比较(PersonRole[]x,PersonRole[]y){
var roleCode=x.First(r=>r.Person==PersonInRole);
var otherRoleCode=y.First(r=>r.Person==PersonInRole);
if(角色代码==其他角色代码)
返回0;
开关(roleCode){
案例“O”:
返回1;
案例“BE”:
返回-1;
案例“CO”:
如果(其他角色代码==“O”)
返回-1;
返回1;
}
}
}

这假设一个人每个帐户只能有一个角色。根据需要进行调整。

您可以使用如下Linq语句:

var givenPerson = "Bob";
Accounts.Where(a => a.PersonRoles.SelectMany(r => r.Person).Contains(givenPerson))
    .OrderBy(a => a, new CustomComparerForRoleCode(givenPerson));
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;
    }
}
要按
AccountRoleCode
进行自定义比较排序,您需要一个比较器类:

public class CustomComparerForRoleCode : IComparer<PersonRole[]>
{
    public string PersonInRole { get; set; }

    public CustomComparerForRoleCode(string personInRole) {
        this.PersonInRole = personInRole;
    }

    public int Compare(PersonRole[] x, PersonRole[] y) {
        var roleCode = x.First(r => r.Person == PersonInRole).AccountRoleCode;
        var otherRoleCode = y.First(r => r.Person == PersonInRole).AccountRoleCode;
        if (roleCode == otherRoleCode)
            return 0;
        switch (roleCode) {
            case "O":
                return 1;
            case "BE":
                return -1;
            case "CO":
                if (otherRoleCode == "O")
                    return -1;
                return 1;
        }
    }
}
公共类CustomComparerForRoleCode:IComparer
{
公共字符串PersonInRole{get;set;}
公共CustomComparerForRoleCode(字符串personInRole){
this.PersonInRole=PersonInRole;
}
公共整数比较(PersonRole[]x,PersonRole[]y){
var roleCode=x.First(r=>r.Person==PersonInRole);
var otherRoleCode=y.First(r=>r.Person==PersonInRole);
if(角色代码==其他角色代码)
返回0;
开关(roleCode){
案例“O”:
返回1;
案例“BE”:
返回-1;
案例“CO”:
如果(其他角色代码==“O”)
返回-1;
返回1;
}
}
}
这假设一个人每个帐户只能有一个角色。根据需要进行调整

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;
    }
}

这样做的好处是

  • 您可以对比较器进行单元测试
  • 同一个类可以有不同的比较器,以防在其他上下文中需要进行不同的排序
  • 如果您发现自己需要在多个地方进行相同的排序,那么将其放在单独的类中可以确保不会重复代码
这是一个令人遗憾的长而复杂的单元测试。但是您必须验证它是否以某种方式工作,这通常比实际运行整个应用程序更容易

[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
语句?(对不起,这既讨厌又没用。我为什么要这样做?)

公共类AccountsByNameComparer:IComparer
{
私有只读字符串\u名称;
私有只读列表\u首选角色序列;
public AccountsByNameComparer(字符串名称,IEnumerable preferredRoleSequence)
{
_名称=名称;
_preferredRoleSequence=preferredRoleSequence.ToList();
}
公共整数比较(账户x、账户y)
{
返回AccountSortValue(x)。与(AccountSortValue(y))进行比较;
}
私人int账户价值(账户)
{
var rolesMatchedByName=account.PersonRoles
.Where(role=>role.Name==\u Name);
var优先角色匹配=
rolesMatchedByName.Select(角色=>
_preferredRoleSequence.IndexOf(role.AccountRoleCode))
.其中(索引=>索引>-1)
.ToArray();
if(preferredRoleMatches.Any())
返回preferredRoleMatches.Min();
返回Int32.MaxValue;
}
}
公共类ExecutiveAccountsByNameComparer:AccountsByNameComparer
{
public ExecutiveAccountsByNameComparer(字符串名称)
:ba