Vojtěch Dohnal
Vojtěch Dohnal

Reputation: 8104

LINQ get the best match from the list comparing strings

I have code where I try to find QProduct by productName in a List<QProduct> (lqp) usinq LINQ. The variable productNameInaccurate I get from file name and often contains some other text usually at the end of the string. So for example the productName = '0/2' and the productNameInaccurate that I get from fileName is '0/2 new' etc.

I have this code:

 //Get inaccurate product name from filename     
 productNameInaccurate = fileName.Substring(ind + 1, ind2 - ind - 1).Replace("-", "/");

 //Get filtered list of products
 List<QProduct> filtered = lqp.Where(x=>productNameInaccurate.StartsWith(x.Name, StringComparison.InvariantCultureIgnoreCase)).ToList();

  //Some more filtering - here I need to get best match by productName
  if (isDop)
         qProduct = filtered.Where(x => x.normy.StartsWith("ČSN EN")).FirstOrDefault();
  else
         qProduct = filtered.Where(x => !x.normy.StartsWith("ČSN EN")).FirstOrDefault();

It works ok, but I have also productName = '32/63' and productName = '32/63 B I'. This code finds QProduct that has productName == '32/63' even if productNameInaccurate == '32/63 BI'.

What I need is to find best match from the list of QProduct, so that for productNameInaccurate='0/2 new' I get QProduct.Name = '0/2' and for productNameInaccurate='32/63 Bi' I get QProduct.Name = '32/63 B II' instead of QProduct.Name = '32/63'. Ideally get the filtered list sorted by count of matching characters.

Upvotes: 2

Views: 1613

Answers (1)

Kyle W
Kyle W

Reputation: 3752

"Ideally get the filtered list sorted by count of matching characters."

// Get the filtered list and sort by count of matching characters
IEnumerable<QProduct> filtered = lqp
    .Where(x=>productNameInaccurate.StartsWith(x.Name, StringComparison.InvariantCultureIgnoreCase))
    .OrderByDesc(x => Fitness(x.ProductName, productNameInaccurate));

static int Fitness(string individual, string target) {
    return Enumerable.Range(0, Math.Min(individual.Length, target.Length))
                     .Count(i => individual[i] == target[i]);
}

Upvotes: 4

Related Questions