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