Home > Enterprise >  Sort array of objects depending on another array values Javascript
Sort array of objects depending on another array values Javascript

Time:03-21

I have two arrays: First array :

SelectedRows= 
[
   {
      "NR":"4",
      "KUNNR":"9?AMT132",
      "NAME":" AUTO TOURING HANDELS GES.M.B.H.",
      "LATLON":[
         15.4114217,
         47.0664085
      ],
      "LIN":"LIN097"
   },
   {
      "NR":"3",
      "KUNNR":"9Z?CH005",
      "NAME":" Z?CHNER ERDBAU U TRANSPORT GMBH",
      "LATLON":[
         13.4216536,
         47.3747925
      ],
      "LIN":"LIN099"
   },
   {
      "NR":"2",
      "KUNNR":"9SMTA001",
      "NAME":" SMT AUTOTEILE",
      "LATLON":[
         13.2277803,
         47.9525892
      ],
      "LIN":"LIN0102"
   },
   {
      "NR":"1",
      "KUNNR":"9REIT051",
      "NAME":" W.REITINGER GMBH",
      "LATLON":[
         14.4017044,
         48.2213305
      ],
      "LIN":"LIN0103"
   }
]

Second array is

LOCATIONS =
[
   [
      15.4114217,
      47.0664085
   ],
   [
      14.4017044,
      48.2213305
   ],
   [
      13.2277803,
      47.9525892
   ],
   [
      13.4216536,
      47.3747925
   ]
]

I need to sort the first array (SelectedRows) on matching values from SelectedRows.LATLON on the second array(LOCATIONS)

I tried to do:

var Output= LOCATIONS.filter(function(obj) { 
            return SelectedRows.LATLON.indexOf(obj) == -1; 
        });

but it did not work. SO if anyone can give me an advice I will be so gratefull. Sorry for my bad english, to get the idea I am posting the expected output:

Expected output :

Output=[
{
    "NR":"4",
    "KUNNR":"9?AMT132",
    "NAME":" AUTO TOURING HANDELS GES.M.B.H.",
    "LATLON":[
        15.4114217,
        47.0664085
    ],
    "LIN":"LIN097"
},
{
    "NR":"1",
    "KUNNR":"9REIT051",
    "NAME":" W.REITINGER GMBH",
    "LATLON":[
        14.4017044,
        48.2213305
    ],
    "LIN":"LIN0103"
},
{
    "NR":"2",
    "KUNNR":"9SMTA001",
    "NAME":" SMT AUTOTEILE",
    "LATLON":[
        13.2277803,
        47.9525892
    ],
    "LIN":"LIN0102"
},
{
    "NR":"3",
    "KUNNR":"9Z?CH005",
    "NAME":" Z?CHNER ERDBAU U TRANSPORT GMBH",
    "LATLON":[
        13.4216536,
        47.3747925
    ],
    "LIN":"LIN099"
}]

Thanks for your help

CodePudding user response:

what you should be doing is to map LOCATIONS

in the map you find the appropriate item in SelectedRows ...

be aware that [1,2] !== [1,2] so you can't compare arrays in your find, since you'll never find anything - either compare each element of the arrays, or, in this case, you could check if array1.join() === array2.join()

const SelectedRows = [ { "NR":"4", "KUNNR":"9?AMT132", "NAME":" AUTO TOURING HANDELS GES.M.B.H.", "LATLON":[ 15.4114217, 47.0664085 ], "LIN":"LIN097" }, { "NR":"3", "KUNNR":"9Z?CH005", "NAME":" Z?CHNER ERDBAU U TRANSPORT GMBH", "LATLON":[ 13.4216536, 47.3747925 ], "LIN":"LIN099" }, { "NR":"2", "KUNNR":"9SMTA001", "NAME":" SMT AUTOTEILE", "LATLON":[ 13.2277803, 47.9525892 ], "LIN":"LIN0102" }, { "NR":"1", "KUNNR":"9REIT051", "NAME":" W.REITINGER GMBH", "LATLON":[ 14.4017044, 48.2213305 ], "LIN":"LIN0103" } ], LOCATIONS = [ [ 15.4114217, 47.0664085 ], [ 14.4017044, 48.2213305 ], [ 13.2277803, 47.9525892 ], [ 13.4216536, 47.3747925 ] ] 

const output =  LOCATIONS.map(
  a=>SelectedRows.find(({LATLON}) => LATLON.join() === a.join())
);

console.log(output);
.as-console-wrapper {max-height: 100%!important; top:0; }
.as-console-row::after { display:none !important; }

Although, for truly readable code

const SelectedRows = [ { "NR":"4", "KUNNR":"9?AMT132", "NAME":" AUTO TOURING HANDELS GES.M.B.H.", "LATLON":[ 15.4114217, 47.0664085 ], "LIN":"LIN097" }, { "NR":"3", "KUNNR":"9Z?CH005", "NAME":" Z?CHNER ERDBAU U TRANSPORT GMBH", "LATLON":[ 13.4216536, 47.3747925 ], "LIN":"LIN099" }, { "NR":"2", "KUNNR":"9SMTA001", "NAME":" SMT AUTOTEILE", "LATLON":[ 13.2277803, 47.9525892 ], "LIN":"LIN0102" }, { "NR":"1", "KUNNR":"9REIT051", "NAME":" W.REITINGER GMBH", "LATLON":[ 14.4017044, 48.2213305 ], "LIN":"LIN0103" } ], LOCATIONS = [ [ 15.4114217, 47.0664085 ], [ 14.4017044, 48.2213305 ], [ 13.2277803, 47.9525892 ], [ 13.4216536, 47.3747925 ] ] 

const output = LOCATIONS.map(([tgtLat, tgtLon]) =>
  SelectedRows.find(
    ({ LATLON: [lat, lon] }) => tgtLat === lat && tgtLon === lon
  )
);

console.log(output);
.as-console-wrapper {max-height: 100%!important; top:0; }
.as-console-row::after { display:none !important; }

CodePudding user response:

Following code is a bit dirty, but it works:

LOCATIONS_ORDER = LOCATIONS.map(e => `${e[0]};${e[1]}`);
SelectedRows.forEach(e => e.index = LOCATIONS_ORDER.indexOf(`${e.LATLON[0]};${e.LATLON[1]}`));

SelectedRows.sort((a,b) => a.index-b.index);

console.log(SelectedRows);

CodePudding user response:

The fastest way (at least asymptotically) to do this in O(n) time given you have n elements both in selectedRows and locations is the following.

  1. Loop over locations which is the correct order and map the location values to the index they are (supposed to be) at. You cannot use the array as such for this as arrays cannot be compared using Object.is() which Map uses internally. So you could for example use a concatenated string here. There may be better/ cleaner options but this is simple and does the job. This will take O(n).

The map then will look like this:

Map(4) {
  '15.4114217,47.0664085' => 0,
  '14.4017044,48.2213305' => 1,
  '13.2277803,47.9525892' => 2,
  '13.4216536,47.3747925' => 3
}
  1. Loop through the selectedRows and for each object determine it's key which is again the location concatenated and using that key get the index the object is supposed to be at in O(1). If the current index and the target index match everything is fine. If not, we need to swap the object to the target index which is obviously done in O(1). This will in total also take O(n).

Done. Combined the steps will take O(n) time and it will therefore be a asymptotically optimal algorithm.

const selectedRows = 
[
   {
      "NR":"4",
      "KUNNR":"9?AMT132",
      "NAME":" AUTO TOURING HANDELS GES.M.B.H.",
      "LATLON":[
         15.4114217,
         47.0664085
      ],
      "LIN":"LIN097"
   },
   {
      "NR":"3",
      "KUNNR":"9Z?CH005",
      "NAME":" Z?CHNER ERDBAU U TRANSPORT GMBH",
      "LATLON":[
         13.4216536,
         47.3747925
      ],
      "LIN":"LIN099"
   },
   {
      "NR":"2",
      "KUNNR":"9SMTA001",
      "NAME":" SMT AUTOTEILE",
      "LATLON":[
         13.2277803,
         47.9525892
      ],
      "LIN":"LIN0102"
   },
   {
      "NR":"1",
      "KUNNR":"9REIT051",
      "NAME":" W.REITINGER GMBH",
      "LATLON":[
         14.4017044,
         48.2213305
      ],
      "LIN":"LIN0103"
   }
]

const locations =
[
   [
      15.4114217,
      47.0664085
   ],
   [
      14.4017044,
      48.2213305
   ],
   [
      13.2277803,
      47.9525892
   ],
   [
      13.4216536,
      47.3747925
   ]
]

console.log("Previous", selectedRows);

const indexMap = new Map();

// Map values to indices
locations.forEach((loc, idx) => indexMap.set(`${loc[0]},${loc[1]}`, idx));

// put each object to the correct position
selectedRows.forEach((row , i) => {
    // concatenate lookup key
    const key = `${row.LATLON[0]},${row.LATLON[1]}`;
    // check if value is actually in map => should always be the case (assumption: locations and showLocation contain the same locations)
    if(indexMap.has(key)){
        const targetIndex = indexMap.get(key);
        // check if the object is at the right position
        if(!targetIndex === i){
            // position is wrong => swap positions
            const temp = selectedRows[i];
            selectedRows[i] = selectedRows[targetIndex];
            selectedRows[targetIndex] = temp;
        }
    }
})

console.log("After", selectedRows);

Note: you would need to make sure that the two variables locations and selectedRows actually contain the same locations and are of equal length.

  • Related