10

I need help sorting through some data. Say I type "piz" in a searchfield. I get in return and array with all the entries that contain "piz".

I now want to display them in the following order:

pizza 
pizzeria
apizzetto
berpizzo

First the items that start with what I typed in alphabetical order then the ones that contain what I typed in alphabetical order.

Instead if I sort them alphabetically I get the following

apizzetto
berpizzo
pizza 
pizzeria

Does anyone know how to do this? Thanks for your help.

Leonardo Amigoni
  • 2,237
  • 5
  • 25
  • 35

5 Answers5

15

You can split the data into two arrays, one that starts with your input and one that doesn't. Sort each separately, then combine the two results:

var data = [
    'pizzeria',
    'berpizzo',
    'apizzetto',
    'pizza'
];

function sortInputFirst(input, data) {
    var first = [];
    var others = [];
    for (var i = 0; i < data.length; i++) {
        if (data[i].indexOf(input) == 0) {
            first.push(data[i]);
        } else {
            others.push(data[i]);
        }
    }
    first.sort();
    others.sort();
    return(first.concat(others));
}

var results = sortInputFirst('piz', data);

You can see it work here: http://jsfiddle.net/jfriend00/nH2Ff/

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Yes, `else` should be `else if indexOf ... > 0` to eliminate non-matching elements. – georg May 13 '12 at 16:19
  • Very nice. Works like a charm. Had to do some modifications to assure lower case matched. But that's a whole other topic. Thank you very much! – Leonardo Amigoni May 13 '12 at 16:37
  • @thg435 - if you read the question carefully, the initial array is already screened to only words that contain the search term. – jfriend00 May 13 '12 at 19:08
  • @jfriend00: I didn't even read the question, to be honest, just glanced over the code and noticed a flaw. – georg May 14 '12 at 08:07
7

The right full solution is:

var data = [
    'pizzeria',
    'berpizzo',
    'apizzetto',
    'pizza'
];

var _sortByTerm = function (data, term) {
    return data.sort(function (a, b) {
       return a.indexOf(term) < b.indexOf(term) ? -1 : 1;
    });
};

var result = _sortByTerm(data, 'piz');

If you want object sort, use this function:

var _sortByTerm = function (data, key, term) {
     return data.sort(function (a, b) {
        return a[key].indexOf(term) < b[key].indexOf(term) ? -1 : 1;
     });
 };
justtal
  • 800
  • 1
  • 7
  • 16
  • 1
    @nickb this is not the correct answer for the OP - while it does address ordering by first index of a term, the OP is essentially asking for two separate sorts, which is the accepted answer. – Randy Hall May 22 '18 at 13:34
  • @RandyHall My mistake -- I was looking for first index of the string match across the board (which seemed logical to me), not first character match, followed by alpha ordering for non-first-character matching strings. Didn't read the question title closely enough. Removed my note. – nickb Jun 10 '18 at 03:12
3

Using reduce:

const data = ['pizzeria', 'berpizzo', 'pizza', 'apizzetto'];

function sortInputFirst(input, data) {
    data.sort();
    const [first, others] = data.reduce(([a, b], c) => (c.indexOf(input) == 0 ? [[...a, c], b] : [a, [...b, c]]), [[], []]);
    return(first.concat(others));
}

const output = sortInputFirst('piz', data);
console.log(output)
kingofbbq
  • 196
  • 1
  • 13
2

Here's another one:

var str = 'piz';
var arr = ['apizzetto','pizzeria','berpizzo','pizza'];

arr.sort(function(a,b) {
    var bgnA = a.substr(0,str.length).toLowerCase();
    var bgnB = b.substr(0,str.length).toLowerCase();

    if (bgnA == str.toLowerCase()) {
        if (bgnB != str.toLowerCase()) return -1;
    } else if (bgnB == str.toLowerCase()) return 1;
    return a < b ? -1 : (a > b ? 1 : 0);
});

console.log(arr);
inhan
  • 7,394
  • 2
  • 24
  • 35
0

Here's how I used the top voted answer to make my search function use a normalized set of data. It removes accents before comparing strings and is also case insensitive.

function getAutocompleteNormalizedMatches(userInput, array) {
    const normalizedInput = getNormalizedString(userInput);
    let normalizedListItem;
    let startsWith = [];
    let anywhere = [];
    for (let i = 0; i < array.length; i++) {
        normalizedListItem = getNormalizedString(array[i]);
        if (normalizedListItem.indexOf(normalizedInput) === 0) {
            startsWith.push(array[i])
        } else if (normalizedListItem.includes(normalizedInput)) {
            anywhere.push(array[i])
        }
    }
    startsWith.sort();
    anywhere.sort();
    return startsWith.concat(anywhere);
}


const getNormalizedString = function (str) {
    str = str.replace(/\s+/g, " ").trim();
    return (str ? removeDiacritics(str.toLowerCase()) : "");
};

To get the removeDiacritics() function, please refer to this link because it takes quite a bit of useless space if you guys don't need it: Remove accents diacritics in a string with JavaScript

Rodger
  • 845
  • 9
  • 21