Amit Pandey
Amit Pandey

Reputation: 314

Sort a json array, first by search text and remaining results alphabetically

I have a json array, which I need to short first based on some search text, and then alphabetically. so basically in below array if I search for "beau" everything starting with beau should be kept on top(sorted alphabetically), and the remaining results will be sorted also alphabetically(even if we have that search text somewhere in the middle of the text) and should start right after the ones

Need solution in Javascript

Array :

[
{
 "value": "1",
 "text": "BEAUMONT Habitation 54"
},
{
 "value": "2",
 "text": "BEAUMONT Place de Renival"
},
{
 "value": "3",
 "text": "BEAUMONT Rue des Tiennes"
},
{
 "value": "4",
 "text": "BEAUMONT Rue Grand Chemin"
},
{
 "value": "5",
 "text": "BRUYERES Chênes"
},
{
 "value": "6",
 "text": "CEROUX Cabine"
},
{
 "value": "7",
 "text": "CEROUX Chapelle aux Sabots"
},
{
 "value": "8",
 "text": "CEROUX Place Communale"
},
{
 "value": "9",
 "text": "CEROUX Quatre Bras"
},
{
 "value": "10",
 "text": "Station Jambeaux"
},
{
 "value": "11",
 "text": "Reseau Street"
},
{
 "value": "12",
 "text": "beaux street"
}
]

EDIT

This is fine, but in another case where I have this data transformed in something like this, this sort is not working

   {
      "item":{
         "value":"1558",
         "text":"BEAUMONT Habitation 54"
      },
      "refIndex":0,
      "matches":[
         {
            "indices":[
               [
                  0,
                  1
               ]
            ],
            "value":"BEAUMONT Habitation 54",
            "key":"text"
         }
      ],
      "score":0.018533147937493524
   },
   {
      "item":{
         "value":"1560",
         "text":"BEAUMONT Place de Renival"
      },
      "refIndex":3,
      "matches":[
         {
            "indices":[
               [
                  0,
                  1
               ]
            ],
            "value":"BEAUMONT Place de Renival",
            "key":"text"
         }
      ],
      "score":0.03162277660168379
   }
]

to make it work I made some changes to the code, but it doesn't seems to work.

function sortByInput(data, input = null) {
  if (!input) {
    return data.sort((a, b) => a.item.text.localeCompare(b.item.text));
  }
  
  return data.sort((a, b) => {
    const regex = new RegExp(`(^${input})`, "i");
    const aMatch = regex.test(a.item.text);
    const bMatch = regex.test(b.item.text);

    if (aMatch || bMatch) return -aMatch + bMatch;

    return a.item.text.localeCompare(b.item.text);
  });
}

Upvotes: 0

Views: 645

Answers (1)

JohannesKantz
JohannesKantz

Reputation: 144

The most basic solution is to use the default Javascript Array.sort method and pass your own compare function.


In the example below I check if there is any input and depending on that I sort just alphabetically, or I sort by input(by checking with the Regular Expression if the element starts with input) and then sort alphabetically.

const data = [
  { value: "1", text: "BEAUMONT Habitation 54" },
  { value: "2", text: "BEAUMONT Place de Renival" },
  { value: "3", text: "BEAUMONT Rue des Tiennes" },
  { value: "4", text: "BEAUMONT Rue Grand Chemin" },
  { value: "5", text: "BRUYERES Chênes" },
  { value: "6", text: "CEROUX Cabine" },
  { value: "7", text: "CEROUX Chapelle aux Sabots" },
  { value: "8", text: "CEROUX Place Communale" },
  { value: "9", text: "CEROUX Quatre Bras" },
  { value: "10", text: "Station Jambeaux" },
  { value: "11", text: "Reseau Street" },
  { value: "12", text: "beaux street" }
];



function sortByInput(data, input = null) {
  if (!input) {
    return data.sort((a, b) => a.text.localeCompare(b.text));
  }
  
  return data.sort((a, b) => {
    const regex = new RegExp(`(^${input})`, "i");
    const aMatch = regex.test(a.text);
    const bMatch = regex.test(b.text);

    if (aMatch || bMatch) return -aMatch + bMatch;

    return a.text.localeCompare(b.text);
  });
}

console.log(sortByInput([...data], "ceroux"));


Edit:

here is an updated version with a third parameter compareValue which specifies the value that it sorts by (I made it default to "item.text" which matches your example)

I also added the function getProp to dynamically get the props of data with the String compareValue

function sortByInput(data, input = null, compareValue = "item.text") {
    const getProp = (object, path) =>
        path.split(".").reduce((o, p) => o[p], object);

    if (!input) {
        return data.sort((a, b) =>
            getProp(a, compareValue).localeCompare(getProp(b, compareValue))
        );
    }

    return data.sort((a, b) => {
        const regex = new RegExp(`(^${input})`, "i");
        const aMatch = regex.test(getProp(a, compareValue));
        const bMatch = regex.test(getProp(b, compareValue));

        if (aMatch || bMatch) return -aMatch + bMatch;

        return getProp(a, compareValue).localeCompare(getProp(b, compareValue));
    });
}

Upvotes: 1

Related Questions