Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Order for autocomplete

Let's say that we have a collection of Humans:

public class Human
{
    public string FirstName { get; set; }
    public string SecondName { get; set; }
    public string CompanyName { get; set; }
}

var people = new List<Human>(){...};

How can we implement autocomplete while sorting people first by FirstName then by SecondName and then by CompanyName?

I tried:

people.Where(x => x.FirstName.StartsWith(term) || x.SecondName.StartsWith(term) 
  ||  x.CompanyName.StartsWith(term))
  .OrderBy(x => x.FirstName).ThenBy(x => x.SecondName).ThenBy(x => x.CompanyName)

But that doesn't work correctly. I want to see only all matched FirstName fields at first then only SecondName fields and so on.

like image 480
Neir0 Avatar asked Feb 20 '23 09:02

Neir0


2 Answers

people.Where(x => x.FirstName.StartsWith(term)).OrderBy(x => x.FirstName)
.Concat(people.Where(x => x.SecondName.StartsWith(term)).OrderBy(x => x.SecondName))
.Concat(people.Where(x => x.CompanyName.StartsWith(term)).OrderBy(x => x.CompanyName))

Add .Distinct() to the end or not depending on whether you want to exclude cases where one person is matched more than one way (in such a case you could also use .Union() instead of .Concat() depending on your source - it's documented as preserving order with enumerable sources, but not with other queryable sources, so it could mess up the ordering depending on the source of people).

like image 195
Jon Hanna Avatar answered Feb 28 '23 15:02

Jon Hanna


I guess you'll want

people.Where(x => x.FirstName.StartsWith(term) ||
                  x.SecondName.StartsWith(term) ||
                  x.CompanyName.StartsWith(term))
    .OrderByDescending(x => x.FirstName.StartsWith(term))
    .ThenByDescending(x => x.SecondName.StartsWith(term))
    .ThenBy(x => x.FirstName)
    .ThenBy(x => x.SecondName)
    .ThenBy(x => x.CompanyName)

This puts

  • Everyone whose first name matches first
  • Then everyone whose second name matches
  • (Then, there'll be everyone whose company name matches)
  • Within this order, it'll then sort by first/last/company name as before.

The yes/no sorts need Descending as false is less than true.

You could possibly optimise this slightly by Selecting an anonymous class with the person and three bools for FirstNameMatches, SecondNameMatches etc., then use these bools in the Where and ordering clauses, thus avoiding calling StartsWith 5 times instead of 3, but you can worry about that when you have the basic sort working.

It'll be trickier if you want to sort the second-name matches by second-name and the company-name matches by company name.

like image 22
Rawling Avatar answered Feb 28 '23 13:02

Rawling