Javascript - 基于 _id 的排序数组对 Javascript 对象进行排序的更快、更有效的方法?
Javascript - Faster, More Efficient Method for Sorting Javascript Object based on Sorted Array of _id?
我们有 MongoDB 个如下所示的文档:
var JavascriptObject = {
DbDocs : [
{
_id : "1",
{..more values..}
},
{
_id : "2",
{..more values..}
},
{
_id : "3",
{..more values..}
}
]
}
根据JavascriptObject
中的某些值,我们从文档中排序一个_id数组,结果是这样的:
var OrderedArray = [ 2, 1, 3 ];
现在,我们正在重建整个 JavascriptObject
,方法是将 OrderedArray
中的 _id 与 DbDocs
中的 _id 进行匹配:
var JavascriptObjectToRebuild = [];
var DbDocuments = JavascriptObject.DbDocs;
var DocumentCount = 0;
for (var OrderedNumber in OrderedArray) {
for (var Document in DbDocuments) {
if ( DbDocuments[Document]._id === OrderedArray[OrderedNumber] ) {
JavascriptObjectToRebuild[DocumentCount] = {}; // new Document Object
JavascriptObjectToRebuild[DocumentCount]._id = DbDocuments[Document]._id;
JavascriptObjectToRebuild[DocumentCount]...more values = DbDocuments[Document]...more values;
DocumentCount++; // increment
}
}
}
var SortedJavascriptObject = { DbDocs: [] }; // format for client-side templating
for (var Document in JSONToRebuild) {
SortedJavascriptObject.DbDocs.push(JavascriptObjectToRebuild[Document]);
}
有没有更快更有效的方法根据这个OrderedArray
对JavascriptObject
进行排序?
如果无法直接排序而必须使用 OrderedArray
,请参阅下面的更新。
如果您可以在 Array#sort
函数的回调中应用您的条件(例如,如果您可以通过将数组中的两个条目相互比较来实现),您可以简单地排序 JSON.DbDocs
直接。
下面是一个根据_id
的数值进行排序的例子;自然地,您会用比较对象的逻辑替换它。
另请注意,我已经更改了顶级变量的名称(JSON
有点用,无论如何,它不是 JSON):
var Obj = {
DbDocs : [
{
_id : "2",
more: "two"
},
{
_id : "1",
more: "one"
},
{
_id : "3",
more: "three"
}
]
};
Obj.DbDocs.sort(function(a, b) {
return +a._id - +b._id; // Replace with your logic comparing a and b
});
document.querySelector('pre').innerHTML = JSON.stringify(Obj, null, 2);
<pre></pre>
如果无法直接排序并且您有从OrderedArray
开始工作,那么使用sort
仍然可以,但不太优雅:你使用 Array#indexOf
找出数组中每个条目的位置:
Obj.DbDocs.sort(function(a, b) {
return OrderedArray.indexOf(+a._id) - OrderedArray.indexOf(+b._id);
});
(+
将 ID 从字符串转换为数字,因为 OrderedArray
在您的问题中包含数字,但 ID 值是字符串。)
实例:
var Obj = {
DbDocs : [
{
_id : "1",
more: "one"
},
{
_id : "2",
more: "two"
},
{
_id : "3",
more: "three"
}
]
};
var OrderedArray = [2, 1, 3];
Obj.DbDocs.sort(function(a, b) {
return OrderedArray.indexOf(+a._id) - OrderedArray.indexOf(+b._id);
});
document.querySelector('pre').innerHTML = JSON.stringify(Obj, null, 2);
<pre></pre>
如果 OrderedArray
中会有很多条目,您可能需要先创建一个查找对象,以避免大量 indexOf
调用(成本高昂:(georg 在回答中这样做了,但他出于某种原因删除了它)
var OrderMap = {}
OrderedArray.forEach(function(entry, index) {
OrderMap[entry] = index;
});
Obj.DbDocs.sort(function(a, b) {
return OrderMap[a._id] - OrderMap[b._id];
});
(我们不需要将 ID 转换为数字,因为 属性 名称始终是字符串,因此我们在构建地图时将数字转换为字符串。)
实例:
var Obj = {
DbDocs : [
{
_id : "1",
more: "one"
},
{
_id : "2",
more: "two"
},
{
_id : "3",
more: "three"
}
]
};
var OrderedArray = [2, 1, 3];
var OrderMap = {}
OrderedArray.forEach(function(entry, index) {
OrderMap[entry] = index;
});
Obj.DbDocs.sort(function(a, b) {
return OrderMap[a._id] - OrderMap[b._id];
});
document.querySelector('pre').innerHTML = JSON.stringify(Obj, null, 2);
<pre></pre>
303 见
......
将OrderedNumber
转换为散列_id => position
:
sorter = {}
OrderedNumber.forEach(function(_id, pos) {
sorter[_id] = pos
})
然后通过比较id的位置对目标数组进行排序:
DbDocuments.sort(function(a, b) {
return sorter[a._id] - sorter[b._id];
})
据我了解,您希望得到这样的结果,
[{"_id":"2"}, {"_id":"1"}, {"_id":"3"}]
所以你可以用一个 forEach
和 indexOf
来做,就像这样
var JSONDADA = {
DbDocs : [{_id : "1",}, {_id : "2"}, {_id : "3"}]
};
var DbDocuments = JSONDADA.DbDocs;
var OrderedArray = [ 2, 1, 3 ];
var result = [];
DbDocuments.forEach(function (el) {
var position = OrderedArray.indexOf(+el._id);
if (position >= 0) {
result[position] = el;
}
});
console.log(JSON.stringify(result));
我们有 MongoDB 个如下所示的文档:
var JavascriptObject = {
DbDocs : [
{
_id : "1",
{..more values..}
},
{
_id : "2",
{..more values..}
},
{
_id : "3",
{..more values..}
}
]
}
根据JavascriptObject
中的某些值,我们从文档中排序一个_id数组,结果是这样的:
var OrderedArray = [ 2, 1, 3 ];
现在,我们正在重建整个 JavascriptObject
,方法是将 OrderedArray
中的 _id 与 DbDocs
中的 _id 进行匹配:
var JavascriptObjectToRebuild = [];
var DbDocuments = JavascriptObject.DbDocs;
var DocumentCount = 0;
for (var OrderedNumber in OrderedArray) {
for (var Document in DbDocuments) {
if ( DbDocuments[Document]._id === OrderedArray[OrderedNumber] ) {
JavascriptObjectToRebuild[DocumentCount] = {}; // new Document Object
JavascriptObjectToRebuild[DocumentCount]._id = DbDocuments[Document]._id;
JavascriptObjectToRebuild[DocumentCount]...more values = DbDocuments[Document]...more values;
DocumentCount++; // increment
}
}
}
var SortedJavascriptObject = { DbDocs: [] }; // format for client-side templating
for (var Document in JSONToRebuild) {
SortedJavascriptObject.DbDocs.push(JavascriptObjectToRebuild[Document]);
}
有没有更快更有效的方法根据这个OrderedArray
对JavascriptObject
进行排序?
如果无法直接排序而必须使用 OrderedArray
,请参阅下面的更新。
如果您可以在 Array#sort
函数的回调中应用您的条件(例如,如果您可以通过将数组中的两个条目相互比较来实现),您可以简单地排序 JSON.DbDocs
直接。
下面是一个根据_id
的数值进行排序的例子;自然地,您会用比较对象的逻辑替换它。
另请注意,我已经更改了顶级变量的名称(JSON
有点用,无论如何,它不是 JSON):
var Obj = {
DbDocs : [
{
_id : "2",
more: "two"
},
{
_id : "1",
more: "one"
},
{
_id : "3",
more: "three"
}
]
};
Obj.DbDocs.sort(function(a, b) {
return +a._id - +b._id; // Replace with your logic comparing a and b
});
document.querySelector('pre').innerHTML = JSON.stringify(Obj, null, 2);
<pre></pre>
如果无法直接排序并且您有从OrderedArray
开始工作,那么使用sort
仍然可以,但不太优雅:你使用 Array#indexOf
找出数组中每个条目的位置:
Obj.DbDocs.sort(function(a, b) {
return OrderedArray.indexOf(+a._id) - OrderedArray.indexOf(+b._id);
});
(+
将 ID 从字符串转换为数字,因为 OrderedArray
在您的问题中包含数字,但 ID 值是字符串。)
实例:
var Obj = {
DbDocs : [
{
_id : "1",
more: "one"
},
{
_id : "2",
more: "two"
},
{
_id : "3",
more: "three"
}
]
};
var OrderedArray = [2, 1, 3];
Obj.DbDocs.sort(function(a, b) {
return OrderedArray.indexOf(+a._id) - OrderedArray.indexOf(+b._id);
});
document.querySelector('pre').innerHTML = JSON.stringify(Obj, null, 2);
<pre></pre>
如果 OrderedArray
中会有很多条目,您可能需要先创建一个查找对象,以避免大量 indexOf
调用(成本高昂:(georg 在回答中这样做了,但他出于某种原因删除了它)
var OrderMap = {}
OrderedArray.forEach(function(entry, index) {
OrderMap[entry] = index;
});
Obj.DbDocs.sort(function(a, b) {
return OrderMap[a._id] - OrderMap[b._id];
});
(我们不需要将 ID 转换为数字,因为 属性 名称始终是字符串,因此我们在构建地图时将数字转换为字符串。)
实例:
var Obj = {
DbDocs : [
{
_id : "1",
more: "one"
},
{
_id : "2",
more: "two"
},
{
_id : "3",
more: "three"
}
]
};
var OrderedArray = [2, 1, 3];
var OrderMap = {}
OrderedArray.forEach(function(entry, index) {
OrderMap[entry] = index;
});
Obj.DbDocs.sort(function(a, b) {
return OrderMap[a._id] - OrderMap[b._id];
});
document.querySelector('pre').innerHTML = JSON.stringify(Obj, null, 2);
<pre></pre>
303 见
......
将OrderedNumber
转换为散列_id => position
:
sorter = {}
OrderedNumber.forEach(function(_id, pos) {
sorter[_id] = pos
})
然后通过比较id的位置对目标数组进行排序:
DbDocuments.sort(function(a, b) {
return sorter[a._id] - sorter[b._id];
})
据我了解,您希望得到这样的结果,
[{"_id":"2"}, {"_id":"1"}, {"_id":"3"}]
所以你可以用一个 forEach
和 indexOf
来做,就像这样
var JSONDADA = {
DbDocs : [{_id : "1",}, {_id : "2"}, {_id : "3"}]
};
var DbDocuments = JSONDADA.DbDocs;
var OrderedArray = [ 2, 1, 3 ];
var result = [];
DbDocuments.forEach(function (el) {
var position = OrderedArray.indexOf(+el._id);
if (position >= 0) {
result[position] = el;
}
});
console.log(JSON.stringify(result));