linq 如何在C#中使用另一个数组按对象数组排序

aydmsdu9  于 2023-02-06  发布在  C#
关注(0)|答案(2)|浏览(201)

示例我有一个数据

Person = [
  {
    Name: "AE1",
    Country: "PH"
  },
  {
    Name: "AE2",
    Country: "LD"
  },
  {
    Name: "AE3",
    Country: "TW"
  },
]

我想按国家排序,比如说我放了一个["TW", "PH", "LD"]的常量数组。
结果将是AE3、AE1、AE2。

tzdcorbm

tzdcorbm1#

您可以使用Array.IndexOf作为排序标准:

string[] countryOrders = {"GB", "TW", "SE"};
var personsByCountry = persons.OrderBy(p => Array.IndexOf(countryOrders, p.Country));

如果某个国家不存在,它将排在前面,因为返回-1。如果您不希望这样:

var personsByCountry = persons
    .Select(p => (Person: p, Order: Array.IndexOf(countryOrders, p.Country)))
    .OrderBy(x => x.Order == -1 ? 1 : 0)
    .ThenBy(x => x.Order)
    .Select(x => x.Person);
m3eecexj

m3eecexj2#

在排序中使用Array.IndexOf()(复杂度为O(N))将使排序复杂度为O(N^2*Log(N)),而不是O(N*Log(N))
如果性能是个问题,你可以通过创建一个查找字典来改善它,这将把复杂性变回O(N*Log(N))

public class Program
{
    public static void Main()
    {
        var persons = new Person[]
        {
            new (Name: "AE1", Country: "PH"),
            new (Name: "AE2", Country: "LD"),
            new (Name: "AE3", Country: "TW")
        };

        string[] sortOrder = { "TW", "PH", "LD" };
        var lookup = new Dictionary<string, int>();

        for (int i = 0; i < sortOrder.Length; i++)
        {
            lookup[sortOrder[i]] = i;
        }

        int indexOfCountry(Person person) => // O(1) complexity.
            lookup.TryGetValue(person.Country, out int index)
                ? index 
                : -1; // Or int.MaxValue if you want missing countries at the end.

        var result = persons.OrderBy(indexOfCountry);

        Console.WriteLine(string.Join("\n", result));
    }
}

public sealed record Person (string Name, string Country);

当然,如果性能真的是个问题,你应该使用Benchmark.net来测试这个方法是否比其他更简单的方法提供了有价值的改进。对于较小的列表,这个方法可能没有什么区别,甚至会让事情变慢。如果你关心性能,你必须执行一些基准测试。

相关问题