3

I have an array containing results form a geolocation code. I want to sort it by the closest match to the term that I have searched.

Example. Search: Pizza.

Array: Pizza Uno, Pizzeria Uno, Burgers and Pizzeria, Cino Pizzeria. 

The sorted array should be:

Pizza Uno,
Pizzeria Uno,
Burgers and Pizzeria,
Cino Pizzeria. 

Thanks for your help.

Michael Berkowski
  • 267,341
  • 46
  • 444
  • 390
Leonardo Amigoni
  • 2,237
  • 5
  • 25
  • 35
  • 1
    You'll have to describe the algorithm you want to use for determining "closest"-ness. Obviously a perfect match can be highest, but what determines the order of the other three items that all have the same partial match? – jfriend00 Dec 09 '11 at 20:37
  • 1
    Why is "Burgers and Pizzeria" a closer match to "Pizza" than "Cino Pizzeria"? – Mark Byers Dec 09 '11 at 20:38
  • Good questions. I don't know what the best algorithm would be. I was thinking of matching the search string and then displaying the ones with same match by alphabetical order. Hence why Burgers and Pizzeria is closer then Cino Pizzeria. Same match but higher in alphabetical – Leonardo Amigoni Dec 09 '11 at 21:09

3 Answers3

3

What about something like this? It was my first approach for getting the closest color name, depending on a hex-color.

There's of course a better solution out there, you could for example take a look at the sift algorithm which is really much faster than levenshtein's approach.

However this should work for you as expected.

Array.closest = (function () {
    function levenshtein(s, t) {
        if (!s.length) return t.length;
        if (!t.length) return s.length;

        return Math.min(
            levenshtein((s.substring(1), t) + 1,
            levenshtein((t.substring(1), s) + 1,
            levenshtein((s.substring(1), t.substring(1)) + (s[0] !== t[0] ? 1 : 0)
        );
    }

    return function (arr, str) {
        return arr.sort(function (a, b) {
            return levenshtein((a, str) - levenshtein((b, str);
        });
    };
}());


var arr = ['Pizza Uno', 'Pizzeria Uno', 'Burgers and Pizzeria', 'Cino Pizzeria.'];
Array.closest(arr, 'Pizza') // => ['Pizza Uno', 'Pizzeria Uno', 'Cino Pizzeria.', 'Burgers and Pizzeria'];
Community
  • 1
  • 1
yckart
  • 32,460
  • 9
  • 122
  • 129
  • There are two problems: Numerous bracketing errors throughout the function and a logic error with your use of 'substring(1)'. substring(1) returns only the second character of any string provided. I cannot tell if what you meant was 'substring(0)' [first char] or something else, but the function does't work as expected in any event. – Evan Dec 22 '13 at 22:10
  • 1
    if the array is longer than 10 to 15 elements, this is damn slow. This also calculates the levenshtein again in every comparison (a-b) (a-c) (a-d) – kaiser Nov 20 '18 at 16:09
3

A really basic algorithm that'd work, would be to sort based on what percentage of the total string length, the match takes up. So an exact match of "Pizza" would be 5/5 (100%), the "Pizza Uno" match would be 5/9, "Pizzeria Uno" is 4/12, and so on. This is one of the core components of the MySQL natural sorting algorithm at its most basic.

Rylab
  • 1,236
  • 7
  • 17
  • Thanks for you answer. That's a very interesting approach. How would I implement that in Javascript. I can't access the google places database directly so I have to sort the results myself. – Leonardo Amigoni Dec 09 '11 at 21:10
1

You can try calculating the Levenshtein Distance between 2 strings. It's basically the number of steps it will take to make the two strings identical.

Pierre
  • 18,643
  • 4
  • 41
  • 62