【问题标题】:Access array of object elements in order from object field? [duplicate]从对象字段按顺序访问对象元素数组? [复制]
【发布时间】:2018-01-15 12:09:09
【问题描述】:

我有一个具有以下 sn-p 的 JS 对象:

{
    "foo": "bar",
    "baz": [
        {
            "order": 2,
            "fruit": "banana"
        },
        {
            "order": 1,
            "fruit": "apple"
        },
        {
            "order": 3,
            "fruit": "peach"
        },
    ]
}

我的目标是能够遍历“baz”中的所有对象,但按照它们的“order”属性的顺序,而不是存储在对象中的顺序。 “baz”中对象的顺序可以/将经常更改,因此不能事先对它们进行排序或按它们需要的顺序存储它们。

纯 JS 或 jQuery 答案都是可以接受的。

【问题讨论】:

  • 使用Array.sortbaz数组进行排序
  • 你卡在哪里了?你试过什么?你的研究结果是什么?当您说““baz”中的对象的顺序可以/将经常更改...”时,您是指它们在数组中的顺序,还是它们的order 属性值?
  • 按顺序显示任何内容意味着首先对其进行排序,即使您是动态进行的。
  • @Sam:来自问题:"...所以之前对它们进行排序...不是一种选择"
  • 如果对它们进行排序是一种选择(根据您的currently accepted answer),下次请不要主动误导我们说这不是一种选择。

标签: javascript jquery arrays sorting javascript-objects


【解决方案1】:

您好,您必须对对象进行排序。只需使用数组的.sort 即可。

这是一个示例:

var obj = {
    "foo": "bar",
    "baz": [
        {
            "order": 2,
            "fruit": "banana"
        },
        {
            "order": 1,
            "fruit": "apple"
        },
        {
            "order": 3,
            "fruit": "peach"
        },
    ]
}

// get property
var arr = obj["baz"];

// may copy array
var counter = arr.length;
var arrCopy = new Array(counter);
while(counter--) {
    arrCopy[counter] = arr[counter];
}

// sort 
arrCopy.sort(function(a, b) { return a.order - b.order});

// iterate it
arrCopy.forEach(function(v) {
  console.log(v.fruit);
})

【讨论】:

  • 来自问题:"...所以之前对它们进行排序或按它们需要的顺序存储它们不是一种选择。"
  • 但是这样做的唯一方法——即使你通过迭代对其进行排序——你也必须对其进行排序!
  • 不,这不是你唯一的选择,而且,OP 再次明确表示他们无法对 baz 进行排序,因此告诉他们对 baz 进行排序是没有用的。
  • 如果无法以正确的顺序存储或不对其进行排序,那么就没有“更好”的解决方案 - 每个解决方案都会变慢。所以这是最好的解决方案之一。而且我不明白为什么不应该使用排序(它只写在问题中,但它仍然是最好的解决方案)
  • 如果无法以正确的顺序存储或不对其进行排序,那么就没有“更好”的解决方案 - 每个解决方案都会变慢。所以这是最好的解决方案之一。而且我不明白为什么不应该使用排序(它只写在问题中,但它仍然是最好的解决方案)
【解决方案2】:

你说过

“baz”中对象的顺序可以/将经常更改...

如果你的意思就是这个意思,而不是他们的order 属性改变,你可以给自己一个另一个 数组,与baz 分开,按顺序包含对象。那么他们在baz中的顺序无关紧要。

var bazInOrder = theObject.baz.slice();
bazInOrder.sort(function(a, b) {
    return a.order - b.order;
});

如果您将条目添加到baz,您需要将其添加(在排序位置)到bazInOrder;同样,如果您从baz 中删除一个条目,您需要从bazInOrder 中删除它。


您的另一个选择是向它们添加一个指向“下一个”条目的属性;例如,在数组上覆盖一个链表。这再次需要在添加/删除时进行相当多的维护,但不仅仅是baz 中的顺序发生变化。

theObject.baz.slice()
         .sort(function(a, b) { return a.order - b.order; })
         .forEach(function(entry, index, arr) {
    entry.next = index < arr.length - 1 ? arr[index + 1] : null;
});

然后按顺序访问它们需要找到order = 1 条目,然后循环使用next

for (var e = theObject.baz.find(function(e) { return e.order === 1; });
     e;
     e = e.next) {
    // ...use `e`...
}

同样,链表涉及添加/删除时的维护。

【讨论】:

  • 来自问题:“......所以之前对它们进行排序或按它们需要的顺序存储它们不是一种选择。”
  • @archos:我没有对baz进行排序。上面的第二种解决方案根本不使用排序数组。
  • 是的,如果您知道数组将/可以在迭代时更改,则应首先复制它(但最好使用 while 循环而不是 slice 大约快 10-30%)。第二个解决方案是按需要的顺序存储它们的部分
  • @archos:嗯,一个单独的索引已经足够远了,这似乎是合理的,而完全做他们说他们不能做的事情却不是。但这没关系,因为这个问题具有误导性并且完全浪费了每个人的时间(基于接受你的答案),因为它只是一个直接的重复。
【解决方案3】:

我猜你可以创建一个数组,其原始索引为baz,顺序为baz[n].order

有点像

var obj = {
    "foo": "bar",
    "baz": [
        {
            "order": 2,
            "fruit": "banana"
        },
        {
            "order": 1,
            "fruit": "apple"
        },
        {
            "order": 3,
            "fruit": "peach"
        },
    ]
}
var bazIndexOrder = obj.baz
  .map(({order}, index) => ({index, order}))
  .sort(({order:a}, {order:b}) => a - b)
  .map(({index}) => index);

console.log(bazOrder); // [1, 0, 2]

bazOrder.forEach(index => console.log(obj.baz[index].fruit)); // apple, banana, peach

如果 ES2015+ 代码让你害怕,那就是

var bazIndexOrder = obj.baz.map(function (_ref, index) {
  var order = _ref.order;
  return { index: index, order: order };
}).sort(function (_ref2, _ref3) {
  var a = _ref2.order;
  var b = _ref3.order;
  return a - b;
}).map(function (_ref4) {
  var index = _ref4.index;
  return index;
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-02
    • 2014-06-10
    • 2011-05-16
    • 2013-11-02
    相关资源
    最近更新 更多