How to sort an array by object value inside a nested array

I am trying to arrange an array of objects in this context of a house, and I am trying to write a function in which users can arrange an array of houses by reference distance. Let's say I have the following data returned by the API that I call through AJAX:

"data" : [ { 'id' : 123, 'address' : '12 street name', 'city' : 'City Name', 'landmarks' : [ { 'name' : 'landmark one', 'distanceInMiles' : 0.6 }, { 'name' : 'landmark two', 'distanceInMiles' : 0.4 } ] }, { 'id' : 345, 'address' : '22 street name', 'city' : 'City Name', 'landmarks' : [ { 'name' : 'landmark one', 'distanceInMiles' : 0.2 }, { 'name' : 'landmark three', 'distanceInMiles' : 0.1 } ] }, { 'id' : 456, 'address' : '28 street name', 'city' : 'City Name', 'landmarks' : [ { 'name' : 'landmark six', 'distanceInMiles' : 8.2 }, { 'name' : 'landmark seven', 'distanceInMiles' : 1.6 } ] } ] 

I already have a code that will return houses containing a specific landmark, for example. filter this array to return houses that have a landmark one landmark, and I store the filtered data in a separate array. But now I want to take another step and order a sorted array of results based on the distanceInMiles value for the selected landmark.

So, adhering to this context, I'm trying to write a code that returns two houses with the address "22 street name", and the house with the address "12 street name" second, since "22 street name", the house is closer to the landmark than the other.

I use _loadash as my utility library, but try to figure out how to sort the filtered array by reference distance. Any ideas?

Any help would be greatly appreciated.

+5
source share
6 answers

 var data = [ { "id" : 123, "address" : "12 street name", "city" : "City Name", "landmarks" : [ { "name" : "landmark one", "distanceInMiles" : 0.6 }, { "name" : "landmark two", "distanceInMiles" : 0.4 } ] }, { "id" : 345, "address" : "22 street name", "city" : "City Name", "landmarks" : [ { "name" : "landmark one", "distanceInMiles" : 0.2 }, { "name" : "landmark three", "distanceInMiles" : 0.1 } ] }, { "id" : 456, "address" : "28 street name", "city" : "City Name", "landmarks" : [ { "name" : "landmark six", "distanceInMiles" : 8.2 }, { "name" : "landmark seven", "distanceInMiles" : 1.6 } ] } ]; function sortByLandmarkDistance(name) { var getDistance = function(house) { var minDistance = Infinity; for(var i = 0; i < house.landmarks.length; ++i) if(house.landmarks[i].name === name) minDistance = Math.min(minDistance, house.landmarks[i].distanceInMiles); return minDistance; }; return data.sort(function(a, b) { return getDistance(a) - getDistance(b); }); } // Sort houses by distance from 'landmark one' var sorted = sortByLandmarkDistance('landmark one'); document.body.innerHTML = '<pre>' + JSON.stringify(sorted, null, ' ') + '</pre>'; 
0
source

Use the array.sort method with a special sort function. Sort is looking for -1 , 0 or 1 . So all you have to do is subtract the distance b from a and alt!

 function sortLandmarkDistanc1 (a, b) { return a.landmarks[0].distanceInMiles - b.landmarks[0].distanceInMiles; } data.sort(sortLandmarkDistanc1); 

 var data = [ { 'id' : 123, 'address' : '12 street name', 'city' : 'City Name', 'landmarks' : [ { 'name' : 'landmark one', 'distanceInMiles' : 0.6 }, { 'name' : 'landmark two', 'distanceInMiles' : 0.4 } ] }, { 'id' : 345, 'address' : '22 street name', 'city' : 'City Name', 'landmarks' : [ { 'name' : 'landmark one', 'distanceInMiles' : 0.2 }, { 'name' : 'landmark three', 'distanceInMiles' : 0.1 } ] }, { 'id' : 456, 'address' : '28 street name', 'city' : 'City Name', 'landmarks' : [ { 'name' : 'landmark six', 'distanceInMiles' : 8.2 }, { 'name' : 'landmark seven', 'distanceInMiles' : 1.6 } ] } ]; function sortLandmarkDistanc1 (a, b) { return a.landmarks[0].distanceInMiles - b.landmarks[0].distanceInMiles; } /* ignore this, just for showing results */ function repeatString(a,c){out="";for(var d=0;d<c;d++)out+=a;return out} function dump(a,c){c="number"!==typeof c?0:c;var d=typeof a,b=d;switch(d){case "number":case "boolean":b+=": "+a;break;case "string":b+="("+a.length+'): "'+a+'"';break;case "object":if(null===a)b="null";else if("[object Array]"===Object.prototype.toString.call(a)){b="array("+a.length+"): {\n";for(d=0;d<a.length;d++)b+=repeatString(" ",c)+" ["+d+"]: "+dump(a[d],"none",c+1)+"\n";b+=repeatString(" ",c)+"}"}else{sContents="{\n";cnt=0;for(var e in a)sContents+=repeatString(" ",c)+" "+e+": "+ dump(a[e],"none",c+1)+"\n",cnt++;sContents+=repeatString(" ",c)+"}";b+="("+cnt+"): "+sContents}}return b}; /*-----------------------*/ document.getElementById('before').innerHTML = dump(data); document.getElementById('after').innerHTML = dump(data.sort(sortLandmarkDistanc1)); 
 <table> <tbody> <tr> <td> <h1>Before</h1> <pre id="before"></pre> </td> <td> <h1>After</h1> <pre id="after"></pre> </td> </tr> </tbody> </table> 
0
source

There is a fairly accurate example of how to do this:

http://www.w3schools.com/jsref/jsref_sort.asp

So, in your case, the function will look something like this:

 var data = getArrayFromAJAXHere(); data.sort(function(a,b){return a.landmarks[0].distanceInMiles - b.landmarks[0].distanceInMiles; }) 

This arranges the array by distance to location in ascending order.

0
source

Make an array of values โ€‹โ€‹paired with an array that counts them (ie [0, 1, 2, ...] ). The code I put in assumes your (filtered) array has this format:

 filtered = [ { id: 123, address: "12 Street Name", city: "City Name", landmark: { name: "landmark One" //and other landmark properties } }, { id: 456, //and so on... 

code:

 var content = []; var order = []; var x; for (x = 0; x < filtered.length; x++) { content[x] = filtered[x].landmark.distanceInMiles; order[x] = x; } var sorted = false; var y; while (!sorted) { sorted = true; for (x = 1; x < content.length; x++) { if (content[x-1] > content[x]) { sorted = false; y = content[x]; content[x] = content[x-1]; content[x-1] = y; y = order[x]; order[x] = order[x-1]; order[x-1] = y; } } } 

Now the order array should contain the correct order of houses, from the smallest to the largest.

0
source

Filtering and sorting:

 // first you call the filter function that will return a new filtered array var myFilteredAndSorteredArray = arr.filter(function(item) { // here, you must return true if the item has the "landmark one" // the map function returns a new array converting for what you're returning // so, you return their names and use the indexOf to see if it has "landmark one" return item.landmarks.map(function(land) { return land.name; }).indexOf("landmark one") > -1; }).sort(function(a, b) { // now you sort the filtered array // so, you use the same map function to get exactly the "landmark one" var landA = a.landmarks[a.landmarks.map(function(land) { return land.name; }).indexOf("landmark one")]; var landB = b.landmarks[b.landmarks.map(function(land) { return land.name; }).indexOf("landmark one")]; // you always compare the second parameter with the first one // since you want to return the smaller distance, you use the < operator return landB.distanceInMiles < landA.distanceInMiles; })); 
0
source

With lodash, you can use filter () and sortBy () as a chain:

 _(data) .filter(function(item) { return _.any(item.landmarks, { name: 'landmark one' }); }) .sortBy(function(item) { return _.find(item.landmarks, { name: 'landmark one' }).distanceInMiles; }) .value(); 
0
source

All Articles