数组:["张三", 2, "李四", 3, "王五", 4]
期望将此数组转换成对象: {"张三": 2, "李四": 3, "王五": 4}
数组:["张三", 2, "李四", 3, "王五", 4]
期望将此数组转换成对象: {"张三": 2, "李四": 3, "王五": 4}
从数组到对象,最直接的方式就是 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}
27 回答13k 阅读
8 回答3.5k 阅读✓ 已解决
6 回答1.3k 阅读✓ 已解决
5 回答5.3k 阅读✓ 已解决
4 回答1.6k 阅读✓ 已解决
3 回答1.7k 阅读
4 回答2.3k 阅读✓ 已解决