[英]Sort an array of objects by property based on another array of reference IDs
我有一个类似的对象数组:
[
{
ref: "CTB98",
name: "Joe"
},
{
ref: "HTF76",
name: "Alice"
},
{
ref: "JHU90",
name: "Tom"
},
{
ref: "ADF56",
name: "Mary"
}
]
在另一个数组中,我具有它们应遵循的确切顺序,并由其ref
属性ref
:
["JHU90", "HTF76", "CTB98", "ADF56"]
我想重新排列第一个对象数组的顺序,以便每个对象上的ref值遵循与我上面的引用数组中的值相同的顺序。
我是计算机科学的新手,所以我将选择对该技术有最佳解释的答案。
排序时,将选择数组中的两个项目,并将它们进行比较以决定哪个应排在最前面。 在这种情况下,必须在引用数组中元素的索引之间进行比较。 因此,您可以像这样对它们进行排序
var data = [{ref: "CTB98", name: "Joe"},
{ref: "HTF76", name: "Alice"},
{ref: "JHU90", name: "Tom"},
{ref: "ADF56", name: "Mary"}],
references = ["JHU90", "HTF76", "CTB98", "ADF56"];
data.sort(function (item1, item2) {
// Index of `item1.ref` in `references` and index of `item2.ref` in
// `references` are used to decide.
return references.indexOf(item1.ref) - references.indexOf(item2.ref);
});
console.log(data);
产量
[ { ref: 'JHU90', name: 'Tom' },
{ ref: 'HTF76', name: 'Alice' },
{ ref: 'CTB98', name: 'Joe' },
{ ref: 'ADF56', name: 'Mary' } ]
注意:由于您是新手,因此建议您阅读此精彩答案 。 这就解释了为什么要减去索引值,以及从比较元素的函数中返回什么。
我认为您想创建由ref
索引的对象的哈希,以防止O(n^2)
时间。
此方法使您可以在O(n)
时间内重新排序,但需要占用O(n)
空间。
var arr = [{ ref: "CTB98", name: "Joe" }, { ref: "HTF76", name: "Alice" }, { ref: "JHU90", name: "Tom" }, { ref: "ADF56", name: "Mary" }]; var order = ["JHU90", "HTF76", "CTB98", "ADF56"]; var result = reorder(arr, order); function reorder(arr, order) { var hash = Object.create(null); arr.forEach(function(obj) { hash[obj.ref] = obj; }); return order.map(function(refKey) { return hash[refKey]; }); } document.getElementById("result").innerHTML = JSON.stringify(result, null, 2);
<pre id="result"></pre>
使用涉及indexOf
或嵌套for循环/ .forEach
各种方法将导致所需的时间以二次方O(n^2)
。 对于n
元素中的每个元素,您可能需要执行n
操作。
创建一个使用每个对象的ref
属性作为该对象的键的哈希对象,可以使ref
查找对象是一个恒定时间操作O(1)
。 哈希的创建是在线性时间O(n)
,因为向哈希对象插入的操作是O(1)
执行n
次。
进行哈希处理后,您可以迭代n
项的“订单”数组,并对每个订单键执行O(1)
查找,以获取最终数组,从而执行另一个O(n)
操作。
因此,此方法的总体时间复杂度将为O(2n)
,仍为O(n)
。
这是一个简化的解释,没有考虑哈希表插入的摊销[1] [2] O(1)
。
基准
function polynomialSort(objs, order) { var arr = []; order.forEach(function(key) { objs.forEach(function(o) { if (o.ref === key) { arr.push(o); } }); }); return arr; } function linearSort(objs, order) { var hash = Object.create(null); objs.forEach(function(el) { hash[el.ref] = el; }); return order.map(function(el) { return hash[el]; }); } var lessObjs = []; var lessOrder = []; for (var i = 1; i < 100; i++) { lessObjs.push({ref:i}); lessOrder.push(i); } shuffle(lessOrder); console.log(100, "items:"); timer(polynomialSort, lessObjs, lessOrder); timer(linearSort, lessObjs, lessOrder); var moreObjs = []; var moreOrder = []; for (var i = 1; i < 10000; i++) { moreObjs.push({ref:i}); moreOrder.push(i); } shuffle(moreOrder); console.log(10000, "items:"); timer(polynomialSort, moreObjs, moreOrder); timer(linearSort, moreObjs, moreOrder); // http://stackoverflow.com/a/6274381/635411 function shuffle(o) { for (var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); return o; } /** * Decorator function for timing a function. * @param {Function} f Function to be timed. */ function timer(f) { console.time(f.name); f.apply(null, [].slice.call(arguments, 1)); console.timeEnd(f.name); }
100 "items:"
polynomialSort: 1.893ms
linearSort: 0.235ms
10000 "items:"
polynomialSort: 1954.783ms
linearSort: 2.205ms
此方法有点精巧,但可以用,因为它取决于JavaScript的Array.prototype.forEach
将按索引顺序遍历元素的原理(请参阅jsfiddle ):
var objs = [
{
ref: "CTB98",
name: "Joe"
},
{
ref: "HTF76",
name: "Alice"
},
{
ref: "JHU90",
name: "Tom"
},
{
ref: "ADF56",
name: "Mary"
}
],
order = ["JHU90", "HTF76", "CTB98", "ADF56"],
arr = [];
order.forEach(function(key) {
objs.forEach(function(o) {
if(o.ref === key) {
arr.push(o);
}
});
});
console.log(arr);
输出:
如果对象和引荐来源网址不匹配,则该选项更为可取。
function sortBy( items , ids ){
let hash = {};
let i = 0;
for( i = 0; i < items.length; i++ ){
hash[ items[i].ref ] = items[i];
}
let orderedItems = [];
for( i = 0; i < ids.length; i++ ){
if( hash[ids[i]] ){
orderedItems.push(hash[ids[i]]);
}
}
return orderedItems;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.