Sorting Array based on property of object on inner array

c# arrays linq sorting

74 观看

2回复

2208 作者的声誉

I have an array of accounts that are returned from our API that have the following data structure.

Accounts[] accounts = [
    {
        AccountNumber: 0000000001,
        PrimaryPerson: Virginia,
        PrimaryPersonNumber: 0001,
        PersonRoleCode: "OWN",
        PersonRoleDescription: "Owner",
        RoleOrder: 1
        PersonRoles: [
                         {
                             AccountRoleCode: "CO",
                             AccountRoleDescription: "Co-Owner",
                             PersonName: "David",
                             PersonNumber: 0002,
                             RoleOrder: 2
                         },
                         {
                             AccountRoleCode: "POA",
                             AccountRoleDescription: "Power of Attorney",
                             PersonName: "Clark",
                             PersonNumber: 0003,
                             RoleOrder: 6
                         }
                     ]
    },
    {
        AccountNumber: 0000000002,
        PrimaryPerson: Clark,
        PrimaryPersonNumber: 0003,
        PersonRoleCode: "OWN",
        PersonRoleDescription: "Owner",
        RoleOrder: 1
        PersonRoles: [
                         {
                             AccountRoleCode: "CO",
                             AccountRoleDescription: "Co-Owner",
                             PersonName: "Virginia",
                             PersonNumber: 0001,
                             RoleOrder: 2
                         },
                         {
                             AccountRoleCode: "POA",
                             AccountRoleDescription: "Power of Attorney",
                             PersonName: "David",
                             PersonNumber: 0002,
                             RoleOrder: 6
                         }
                     ]
    },   
    {
        AccountNumber: 0000000003,
        PrimaryPerson: David,
        PrimaryPersonNumber: 0002,
        PersonRoleCode: "OWN",
        PersonRoleDescription: "Owner",
        RoleOrder: 1
        PersonRoles: [
                         {
                             AccountRoleCode: "CO",
                             AccountRoleDescription: "Co-Owner",
                             PersonName: "Clark",
                             PersonNumber: 0003,
                             RoleOrder: 2
                         },
                         {
                             AccountRoleCode: "CO",
                             AccountRoleDescription: "Co-Owner",
                             PersonName: "Virginia",
                             PersonNumber: 0001,
                             RoleOrder: 2
                         },
                         {
                             AccountRoleCode: "POA",
                             AccountRoleDescription: "Power of Attorney",
                             PersonName: "Virginia",
                             PersonNumber: 0001,
                             RoleOrder: 6
                         }
                     ]
    }
];

I need to sort this Accounts object based on the RoleOrder for the Accounts object itself, and the RoleOrder for the PersonRole object in each PersonRoles[] index.

I've tried to do it with LINQ, but I'm unsure why it's not working correctly.

Here's what I tried and what I expected it to do.

IEnumberable<Account> sortedAccounts = accounts
    .OrderBy(acct => acct.PersonRoles
    .Where(role => role.PersNbr == 0001)
    .Select(x => x.RoleOrder)).ToList();

I expected it to order the main accounts[] by the PersonRoles[] where the PersNbr is equal to the given PersNbr (0001), and sort on the RoleOrder.

So basically I want to sort the accounts[] based on the RoleOrder for a specific person only.

So sorting based on Virginia will result in Accounts[] accounts = [0000000001, 0000000003, 0000000002]

Sorting based on David will result in Accounts[] accounts = [0000000003, 0000000001, 0000000002]

What I have for LINQ isn't doing anything (order remains the same), which makes me think I'm doing doing the query in the correct order.

How do I write a LINQ query to do this, or do I need to split it up into different queries?

作者: Jimenemex 的来源 发布者: 2017 年 12 月 27 日

回应 2


1

26 作者的声誉

决定

I've been asked to provide a full answer, here we go:

First, I would like to draw your attention to a "design hole" that you have: what happens if you don't have this "person" at all? for this case, I've allowed myself to assume that all those results would be shown at the end.

About the problem: the complexity of the problem comes from you need to perform two different sorting: during the Account[] array sorting, and also inside the PersonRoles array inside each account, while both of the sortings has the same logic.

Assuming that your object is mutable, I am recommending the next solution:

IEnumerable<Account> sortedAccounts = accounts
            .Select(x => {
                x.PersonRoles = x
                .PersonRoles
                .OrderBy(acct => {
                    if (acct.PersonNumber != 001)
                        return 999;
                    return acct.RoleOrder;
                }).ToArray();
                return x;
            })
            .OrderBy(acct => {                
                var relevantRoles = acct.PersonRoles
                    .Where(role => role.PersonNumber == 0001)
                    .Select(x => x.RoleOrder);
                if (relevantRoles.Any() == false)
                    return 999;
                return relevantRoles.Max();
                }
            ).ToList();

Explanations: We start from the "select" statement, in which we reorder the internal structure of the PersonRoles arrays inside each account, this way it's clearer and will help to perform the accounts ordering a bit simpler

Later, we order the accounts array according to the same logic

Note that istead of the "return 999" statements, you could write some other logic that will address cases when there are no relevan users inside the PersonRoles array.

作者: user2828545 发布者: 2017 年 12 月 27 日

1

159 作者的声誉

See: Sort a list and all its nested objects using Linq

You can do it in one statement. Inside of each LINQ, you need to create new objects using information from the outer statement.

class Account
{
    public int AccountNumber { get; set; }
    public Role[] Roles { get; set; }
}

class Role
{
    public string State { get; set; }
    public int RoleOrder { get; set; }
}

Account[] accounts = new Account[3];
        accounts[0] = new Account { AccountNumber = 1, Roles = new 
Role[2] { new Role { State = "AK", RoleOrder = 2 }, new Role { State = 
"CO", RoleOrder = 1 } } };
        accounts[1] = new Account { AccountNumber = 3, Roles = new 
Role[2] { new Role { State = "NY", RoleOrder = 66 }, new Role { State = 
"FL", RoleOrder = 5 } } };
        accounts[2] = new Account { AccountNumber = 2, Roles = new 
Role[2] { new Role { State = "CA", RoleOrder = 9 }, new Role { State = 
"AZ", RoleOrder = 8 } } };

IEnumerable<Account> info = accounts
    .Select(x => new Account { 
        AccountNumber = x.AccountNumber
        , Roles = x.Roles.OrderBy(y => y.RoleOrder).ToArray() 
    }
    ).Where(x => x.AccountNumber == 2);
作者: Snake_Plissken 发布者: 2017 年 12 月 27 日
32x32