如何根据嵌套数组中对象的值对数组进行排序
How to sort an array by the value of an object within a nested array
我正在尝试对一组对象(在此上下文中的房屋)进行排序,并且我正在尝试编写一个函数,用户可以在其中根据地标的距离对一组房屋进行排序。假设我有以下数据 return 从我通过 AJAX 调用的 API 编辑:
"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
}
]
}
]
我已经有一些代码可以 return 包含特定地标的房屋,例如将此数组过滤为 return 个具有地标 "landmark one" 的房屋,然后我将过滤后的数据存储到一个单独的数组中。但我现在想更进一步,根据所选地标的 distanceInMiles
值对过滤后的结果数组进行排序。
所以,根据这个上下文,我正在尝试编写一些代码,将 return 地址为“22 street name”的两栋房子放在第一位,地址为“12 street name”的房子放在第二位,因为“22 街道名称”房子比另一个更接近地标。
我正在使用 _loadash 作为我的实用程序库,但很难理解如何按 "landmark one" 距离对过滤后的数组进行排序。有什么想法吗?
如有任何帮助,我们将不胜感激。
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>';
使用带有自定义排序功能的 array.sort 方法。排序查找 -1
、0
或 1
。所以你所要做的就是从 a
和 viola!
中减去距离 b
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>
这里有一个非常准确的例子来说明如何做到这一点:
http://www.w3schools.com/jsref/jsref_sort.asp
所以,在你的例子中,函数看起来像这样:
var data = getArrayFromAJAXHere();
data.sort(function(a,b){return a.landmarks[0].distanceInMiles - b.landmarks[0].distanceInMiles; })
这将按位置的距离升序排列数组。
将值与计数它们的数组配对(即 [0, 1, 2, ...]
)。我提供的代码假定您的(过滤后的)数组是这种格式:
filtered = [
{
id: 123,
address: "12 Street Name",
city: "City Name",
landmark: {
name: "landmark One"
//and other landmark properties
}
}, {
id: 456,
//and so on...
代码:
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;
}
}
}
现在数组 order
应该包含正确的房屋顺序,从小到大。
筛选和排序:
// 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;
}));
使用 lodash,您可以将 filter() and sortBy() 用作链:
_(data)
.filter(function(item) {
return _.any(item.landmarks, {
name: 'landmark one'
});
})
.sortBy(function(item) {
return _.find(item.landmarks, {
name: 'landmark one'
}).distanceInMiles;
})
.value();
我正在尝试对一组对象(在此上下文中的房屋)进行排序,并且我正在尝试编写一个函数,用户可以在其中根据地标的距离对一组房屋进行排序。假设我有以下数据 return 从我通过 AJAX 调用的 API 编辑:
"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
}
]
}
]
我已经有一些代码可以 return 包含特定地标的房屋,例如将此数组过滤为 return 个具有地标 "landmark one" 的房屋,然后我将过滤后的数据存储到一个单独的数组中。但我现在想更进一步,根据所选地标的 distanceInMiles
值对过滤后的结果数组进行排序。
所以,根据这个上下文,我正在尝试编写一些代码,将 return 地址为“22 street name”的两栋房子放在第一位,地址为“12 street name”的房子放在第二位,因为“22 街道名称”房子比另一个更接近地标。
我正在使用 _loadash 作为我的实用程序库,但很难理解如何按 "landmark one" 距离对过滤后的数组进行排序。有什么想法吗?
如有任何帮助,我们将不胜感激。
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>';
使用带有自定义排序功能的 array.sort 方法。排序查找 -1
、0
或 1
。所以你所要做的就是从 a
和 viola!
b
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>
这里有一个非常准确的例子来说明如何做到这一点:
http://www.w3schools.com/jsref/jsref_sort.asp
所以,在你的例子中,函数看起来像这样:
var data = getArrayFromAJAXHere();
data.sort(function(a,b){return a.landmarks[0].distanceInMiles - b.landmarks[0].distanceInMiles; })
这将按位置的距离升序排列数组。
将值与计数它们的数组配对(即 [0, 1, 2, ...]
)。我提供的代码假定您的(过滤后的)数组是这种格式:
filtered = [
{
id: 123,
address: "12 Street Name",
city: "City Name",
landmark: {
name: "landmark One"
//and other landmark properties
}
}, {
id: 456,
//and so on...
代码:
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;
}
}
}
现在数组 order
应该包含正确的房屋顺序,从小到大。
筛选和排序:
// 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;
}));
使用 lodash,您可以将 filter() and sortBy() 用作链:
_(data)
.filter(function(item) {
return _.any(item.landmarks, {
name: 'landmark one'
});
})
.sortBy(function(item) {
return _.find(item.landmarks, {
name: 'landmark one'
}).distanceInMiles;
})
.value();