1

Example I have a data

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

I want to order it by country lets say I put an const array of ["TW", "PH", "LD"].

The result would be AE3, AE1, AE2.

2
  • What should happen if you use an array of ["GB", "TW", "SE"]? Commented Feb 2, 2023 at 8:36
  • Then the order would be AE3 first then followed by AE1 or AE2. Since GB and SE is not on the Country list. Commented Feb 2, 2023 at 8:39

2 Answers 2

5

You can use Array.IndexOf as sort criteria:

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

If a country does not exists it would come first, because -1 is returned. If you don't want that:

 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);
Sign up to request clarification or add additional context in comments.

Comments

1

Using Array.IndexOf() (which has O(N) complexity) within a sort will make the sort complexity O(N^2*Log(N)) rather than O(N*Log(N))complexity.

If performance is an issue you can improve this by creating a lookup dictionary to use when sorting. This will change the complexity back to 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);

Of course, if performance really is an issue you should use Benchmark.Net to test whether this provides a worthwhile improvement over other, simpler approaches. For smaller lists, this approach is likely to make little difference or even make things slower. You MUST execute some benchmarks if you care about performance.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.