JavaScript将数组转换成对象?

新手上路,请多包涵

数组:["张三", 2, "李四", 3, "王五", 4]
期望将此数组转换成对象: {"张三": 2, "李四": 3, "王五": 4}

阅读 2.6k
4 个回答
var arr = ["张三", 2, "李四", 3, "王五", 4]
var obj = {}
while(arr.length) {
  obj[arr.shift()] = arr.shift()
}

从数组到对象,最直接的方式就是 Object.fromEntries(),只是这个方法需要的参数格式比较严格,需要是 entry(pair) 的数组,而 entry 可以看作是一个二元组(JS 只能用 2 个元素的数组来表示)。因此,entry 数组本质上是一个数组的数组,要使用 Object.fromEntries() 就必须要把原数组构造成 entry 数组。

观察,这个原数组还是很有规律的,偶数索引上是 Key,奇数索引是 Value,用循环构造肯定是没问题的

const entries = [];
for (let i = 0; i < data.length; i += 2) {
    entries.push([data[i], data[i + 1]]);
}
return entries;

也可以用 Map 的形式,先构造一个一半长度的数组,然后把每个元素在映射过程中构造出来

const entries = Array.from(
    { length: ~~(data.length / 2) },
    (_, i) => [data[i + i], data[i + i + 1]]
)
这里没用 i * 2 而是用的 i + i 是因为一般认为加法会比乘法快(但 *2 比较特殊,要看 Runtime 是否有做优化)。当然更快是直接用位运算,这个理解起来可能会难一点。

当然对于常规的数据操作,不妨利用工具。Lodash 就很好,它提供了 _.chunk() 工具函数直接就可以按固定数量对数组进行分组

const entries = _.chunk(data, 2);

之后使用 Object.fromEntries(entries) 就可以得到对象。

顺便,使用 Lodash 的 Lazy 计算,可以完整的写出来

_(data).chunk(2).fromPairs().value();

当然 Object.fromEntries 不是唯一方法。比如上面第一个循环,既然可以构造 entry 数组,那直接构造对象也是没问题,甚至更快

const obj = (data => {
    const it = {};
    for (let i = 0; i < data.length; i += 2) {
        it[data[i]] = data[i + 1];
    }
    return it;
})(data);

但这个问题用 reduce 并不是很适合,可以做出来。reduce 适合做单纯的迭代过程,但这个问题需要对奇偶进行单独处理。

下面这个方式是在偶数索引上处理,通过 arr 参数去拿下一个迭代项;奇数索引直接跳过。

const obj = data.reduce((r, it, i, arr) => {
    if (i % 2 === 0) {
        r[it] = arr[i + 1];
    }
    return r;
}, {});

还有一种方式是在奇数索引上处理,偶数索引拿到的 Key 缓存起来。注意初始值是一个数组,前一个元素是最终结果,后一个元素是缓存的 key。

const obj = data.reduce(
    (r, it, i) => {
        if (i % 2 === 0) {
            r[1] = it;
        } else {
            r[0][r[1]] = it;
        }
        return r;
    },
    [{}, undefined]
)[0];

最后再提一下 Generator,本质上和第一个循环处理没有区别

@zangeci 启发,改了下 generator,浅拷贝了 data,免得修改原数组。
function* iterate(data) {
    const serials = [...data];
    while (serials.length) {
        yield [serials.shift(), serials.shift()];
    }
}

const obj = Object.fromEntries([...iterate(data)]);
// i = 0  返回 {}
// i = 1  返回 {张三: '2'}
// i = 2  返回 {张三: '2'}
// i = 3  返回 {张三: '2', 李四, 3}
// i = 4  返回 {张三: '2', 李四, 3}
// i = 5  返回 {张三: '2', 李四, 3, 王五: 4}
let arr = ["张三", 2, "李四", 3, "王五", 4]
let list = arr.reduce((s, v, i) => {
    i % 2 && (s[arr[i - 1]] = v)
    return s
}, {})
console.log(list)
let arr = ["张三", 2, "李四", 3, "王五", 4]
let list = Object.fromEntries(arr.slice(arr.length / 2).map((v, i) => arr.slice(i*2, i * 2 + 2)))
console.log(list)

倒是可以用 Object.fromEntries() 来处理,但是需要整理你的数组为二维数组,所以倒不如直接写 for 循环了。

var a = ["张三", 2, "李四", 3, "王五", 4]
var b = {}
for(let i = 0; i < a.length; i += 2) {
  b[a[i]] = a[i+1]
}
console.log(b)
// {张三: 2, 李四: 3, 王五: 4}

如果说提供的数组是 [["张三", 2], ["李四", 3], ["王五", 4]] 这样的,那么就可以很简单的处理了。

var a = [["张三", 2], ["李四", 3], ["王五", 4]]
var b = Object.fromEntries(a)
console.log(b)
// {张三: 2, 李四: 3, 王五: 4}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏