【问题标题】:Javascript - Faster, More Efficient Method for Sorting Javascript Object based on Sorted Array of _id?Javascript - 基于 _id 的排序数组对 Javascript 对象进行排序的更快、更有效的方法?
【发布时间】:2015-10-30 12:47:32
【问题描述】:

我们有如下所示的 MongoDB 文档:

var JavascriptObject = {
  DbDocs : [
    {
      _id : "1",
      {..more values..}
    },
    {
      _id : "2",
      {..more values..}
    },
    {
      _id : "3",
      {..more values..}
    }
  ]
}

根据JavascriptObject中的某些值,我们从文档中订购一个_id的数组,结果是这样的:

var OrderedArray = [ 2, 1, 3 ];

现在,我们正在通过将OrderedArray 中的_id 与DbDocs 中的_id 匹配来重建整个JavascriptObject

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]);
}

有没有更快更有效的方法来根据这个OrderedArrayJavascriptObject进行排序?

【问题讨论】:

  • _id 是独一无二的属性吗?
  • 这个问题根本没有JSON。 JSON 是一种文本 表示法。当您在 JavaScript 中处理对象和数组时,您就是在处理 JavaScript 对象和数组。您在 JavaScript 代码中处理 JSON 的唯一时间是它在 string 中。
  • 有什么理由不能直接在JSON.DbDocs 上拨打sort 吗?
  • @Maji:我已经更新了我的答案以展示如何将OrderedArraysort 一起使用,但如果您可以直接而不是间接地实现排序逻辑,它可能会更好。显然,由于问题之外的原因,这可能是不可能的或不可取的......
  • @Akxe:这是 georg 在他的回答中所做的。 :-)

标签: javascript arrays sorting javascript-objects


【解决方案1】:

如果无法直接排序,请参阅下面的更新,您必须改用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>

【讨论】:

  • 感谢您的详尽.. Obj.DbDocs.sort(function(a, b) { return OrderedArray.indexOf(+a._id) - OrderedArray.indexOf(+b._id); }); 就像一个魅力
【解决方案2】:

据我了解,您希望得到这样的结果,

[{"_id":"2"}, {"_id":"1"}, {"_id":"3"}]

所以你可以用一个forEachindexOf 来做到这一点,就像这样

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));

【讨论】:

    【解决方案3】:

    303 见other

    ......

    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];
    })
    

    【讨论】:

    • 是的,如果OrderedArray 大小合适,这可能会使sort 更有效率。
    猜你喜欢
    • 1970-01-01
    • 2013-03-13
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-25
    • 2022-06-17
    相关资源
    最近更新 更多