如何防止lodash mapKeys重新排序我的数组?

时间:2016-11-02 19:18:39

标签: javascript underscore.js lodash

我使用lodash mapKeys获取我的对象数组,并使用id属性将其转换为映射对象。这很简单,但问题是它按id对新对象进行排序。

例如,如果我的数组中有三个对象:

let myArray = [
    {
        id: 3,
        name: 'Number Three'
    },
    {
        id: 1,
        name: 'Number One'
    },
    {
        id: 2,
        name: 'Number Two'
    }
];

然后我按id映射键:

_.mapKeys(myArray, 'id')

返回以下内容:

{
    1: {
        id: 1,
        name: 'Number One'
    },
    2: {
        id: 2,
        name: 'Number Two'
    },
    3: {
        id: 3,
        name: 'Number Three'
    }
}

我的服务器以特定的顺序返回数组,所以我希望这些对象保持不变,这样当我遍历对象属性时,它们的顺序正确。

这种方法有可能吗?如果没有,是否有可能的替代方案来实现结果?

3 个答案:

答案 0 :(得分:1)

使用Map,因为每个项目都有自定义键(如对象),但插入顺序将是迭代的顺序(如数组):

const myArray = [
    {
        id: 3,
        name: 'Number Three'
    },
    {
        id: 1,
        name: 'Number One'
    },
    {
        id: 2,
        name: 'Number Two'
    }
];

const map = myArray.reduce((map, item) => map.set(item.id, item), new Map());

map.forEach((item) => console.log(item));

答案 1 :(得分:0)

如评论中所提到的,最好的方法是将对象引用保留在数组中以保持顺序,并使用哈希来简化更新。

Backbone's collectionsource)就是这样的。它将对象保留在数组(models)中,但在添加和删除模型(对象)时或模型的ID更改时自动更新哈希(_byId)。

这是概念的简单实现。您可以进行自己的实现或检查集合库。



// a little setup
var array = [];
var hash = {};

var addObject = function addObject(obj) {
  hash[obj.id] = obj;
  array.push(obj);
}

// Create/insert the objects once
addObject({ id: 3, name: 'Number Three' });
addObject({ id: 1, name: 'Number One' });
addObject({ id: 2, name: 'Number Two' });

// Easy access by id
console.log("by id with hash", hash['1']);

// updating is persistent with the object in the array
hash['1'].name += " test";

// keeps the original ordering
for (var i = 0; i < 3; ++i) {
  console.log("iterating", i, array[i]);
}
&#13;
&#13;
&#13;

答案 2 :(得分:0)

正如评论中所指出的,循环对象并不能保证秩序。如果你想要一个有序列表,你需要一个数组。

但是,您可以应用迭代器模式。在这种模式中,由您来决定“下一个”元素是什么。因此,您可以拥有一个包含对象的集合(为了使它们保持恒定时间)和一个用于存储订单的数组。要迭代,您可以使用迭代器。

此代码可用作示例。

希望它有所帮助。

&#13;
&#13;
let myArray = [{
  id: 3,
  name: 'Number Three'
}, {
  id: 1,
  name: 'Number One'
}, {
  id: 2,
  name: 'Number Two'
}];

let myIterator = ((arr) => {
  let mySet = _.mapKeys(arr, 'id'),
    index = 0,
    myOrder = _.map(arr, _.property('id'));

  return {
    getObjById: (id) => mySet[id],
    next: () => mySet[myOrder[index++]],
    hasNext: () => index < myOrder.length
  };
})(myArray);

// Access elements by id in constant time.
console.log(myIterator.getObjById(1));

// Preserve the order that you got from your server.
while (myIterator.hasNext()) {
  console.log(myIterator.next());
}
&#13;
<script src="https://cdn.jsdelivr.net/lodash/4.16.6/lodash.min.js"></script>
&#13;
&#13;
&#13;