如何从键值对数组创建对象?

Posted

技术标签:

【中文标题】如何从键值对数组创建对象?【英文标题】:How to create an object from an Array of key-value pairs? 【发布时间】:2013-12-02 07:46:22 【问题描述】:

在 Python 中,可以向 dict1 构造函数传递一系列键值对:

>>> dict([['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']])
'age': 42, 'name': 'Bob', 'breakfast': 'eggs'

除了为此目的定义我自己的函数之外,我想不出任何办法在 javascript 中做这种事情:

function pairs_to_object(pairs) 
    var ret = ;
    pairs.forEach(function (p)  ret[p[0]] = p[1]; );
    return ret;

但我是一个 JS 菜鸟......这种排序对到对象的转换有什么内置的吗?

1 出于这个问题的目的,我将 Python dicts 视为 Python 的 JS 对象对应物,尽管相似之处当然仅限于它们都是键值集合。

【问题讨论】:

“这种排序对到对象的转换是否有内置的东西?” 不是纯 JavaScript。 一些图书馆提供它:underscorejs.org/#object 有一个 ES proposal 将其添加到 JS 为 Object.fromEntries 这是 Object.entries 函数在 ES2017 中添加到 JS 中的反函数。 【参考方案1】:

在撰写本文时 (2013),JavaScript 对象/字典/关联数组本身没有这样的构造函数。

正如您自己所说,您当然可以使用例如使用 reduce 函数的函数方法构建自己的函数,如其他答案之一中所述。当然,经典的 for 或更新的 forEach 循环也可以工作。但是没有任何内置的东西。


编辑:现在是 2019 年,现在我们有 Object.fromEntries,它将为您提供所需的一切。

【讨论】:

【参考方案2】:

Javascript 没有按照您描述的方式将数组转换为对象的本机函数。但是,这是因为不需要它。您已经在问题中包含了一个示例解决方案,您可以在其中自己定义函数,但这实际上不是必需的。只要您可以确定输入数组是正确的,您甚至可以使用简单的 for 循环进行转换,如下所示:

var input = [['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']];
var output = ;
for(i in input) output[input[i][0]] = input[i][1];

这只是可以想象的最基本的代码。

当然,(正如 mamapitufo 指出的那样)实际使用 for..in 遍历数组通常是一个坏主意,因为这也会返回非索引作为 i 的值。不过,关键是这种操作过于简单,而且很少需要,不足以证明拥有原生函数是合理的。

python dict 是 javascript 中不需要的结构,因为这两种语言在输入和设计方面有不同的方法,所以对一个有用的对另一个没有用。虽然您可以使用在 python 中使用的相同方法和结构,但考虑如何利用 javascript 的不同做事方式可能是一个更好的主意 - 也许您会发现您不需要 dict毕竟。

【讨论】:

在 ES5 中有 is Array.prototype.forEach:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 不建议在 JavaScript 中使用 'for .. in' 来遍历数组中的元素:***.com/a/500531/421089 @mamapitufo 你是完全正确的,谢谢,我已经编辑了答案以澄清我想说的。 > python dict是javascript中不需要的结构 真的吗?所以,目前我有一个键值对列表。我有一个 中每个 @Lucretiel 在 javascript 中执行此操作的方法通常是使用对象,因为 javascript 中的数组非常有限,并且不能关联。 Javascript 不需要显式的字典类,因为所有对象本身都是字典。它们也可以是类、函数和原语,有时同时是所有这些——我承认这可能会让人很困惑,但一旦你弄清楚了,它们就会非常灵活。【参考方案3】:

你可以使用reduce函数

x = [[1,2],[3,4],[5,6]];
o = x.reduce(function(prev,curr)prev[curr[0]]=curr[1];return prev;,)

o 现在相当于1:2, 3:4, 5:6

如果您的输入数组是稀疏的,您需要在分配上添加一个if(curr!=undefined) 测试,但请确保您仍然返回“prev”。

如果您的元组比简单的 [key,value] 更复杂,您可以简单地更改“prev”的分配方式。例如:prev["key-"+curr[0].toString()]=curr[1]*2;

【讨论】:

这是最好的答案,因为它适用于所有浏览器,并且非常紧凑。每个人都应该学习 map、filter 和 reduce。我花了一段时间才找到结尾的 ,它为 reduce 提供了初始值。此外,粗箭头语法会使其更具可读性,但不适用于所有浏览器。【参考方案4】:

Object.fromEntries 完成这项工作。它是通过 EcmaScript2019 添加到语言中的。

如果您不支持该功能,您可以使用以下 ES2015 代码自行定义:

Object.fromEntries = arr => Object.assign(, ...Array.from(arr, ([k, v]) => ([k]: v) ));

好消息是这个方法与Object.entries(ES2017)相反,所以现在你可以在对象和数组表示之间来回切换:

const arr = [['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']];
const obj = Object.fromEntries(arr);
console.log(obj);
// ... and back:
const arr2 = Object.entries(obj);
console.log(arr2); // copy of the original array (omitting duplicate keys)
.as-console-wrapper  max-height: 100% !important; top: 0; 

ES6 地图

对于键/值对,有一个普通对象的替代方案:Map

它的构造函数接受数组对格式:

// Demo:
const arr = [['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']];

const mp = new Map(arr);

// Get one particular value:
console.log(mp.get('age'));
// Get all the keys:
console.log(...mp.keys());
// Get all the values:
console.log(...mp.values());
// Get all the key/value pairs:
console.log(...mp.entries());

如果你真的需要一个普通的对象,那么这没什么用,但 Map 可能是一个可行的替代方案。

【讨论】:

不幸的是,如果要将 Map 序列化为 JSON,则需要额外的工作。否则你的解决方案很酷! +1 谢谢@Kostanos。幸运的是,我的答案的主要 (Object.assign) 部分可用于生成 JSON ;-) 映射具有其他特性(如方便的构造函数,保持插入顺序,允许非字符串作为键,提供 size 属性, ...) 在某些用例中可能很有趣。 这太棒了!谢谢!我对如何/为什么使用方括号作为键(即[k]: v)有点困惑。这是破坏性的东西吗?我一直在努力想弄清楚如何以这种方式使用变量作为键,当我看到这有效时,我很困惑,但仍然很高兴。 我会继续自己回答这个问题...不,不完全是...任何好奇的人都可以查看这篇文章:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…。相关位是:“从 ECMAScript 2015 开始,对象初始化器语法也支持计算属性名称。这允许您将表达式放在括号 [] 中,它将被计算并用作属性名称。”我非常喜欢 ES20xx... 2018 ES草案中,可以使用object spread syntax代替Object.assign,如下:<array>.reduce((o, [k, v]) => (...o, [k]: v), )【参考方案5】:

Lodash 的 fromPairs 函数会这样做:

const _ = require('lodash')
const kvPairs = [['a', 1], ['b', 2]]
_.fromPairs(kvPairs)
// =>  a: 1, b: 2 

【讨论】:

【参考方案6】:

Object.fromEntries()

Object 对象上有一个名为Object.fromEntries(iterable) 的方法。来自可迭代对象的迭代器对象必须生成一个包含 2 个元素的数组。第一个(索引 0)数组元素将是对象键,第二个是值。

MDN 非常准确地描述了这一点:

Object.fromEntries() 方法采用键值对列表和 返回一个新对象,其属性由这些条目给出。这 可迭代参数应该是一个实现 @@iterator 方法,它返回一个迭代器对象,它产生一个 二元素数组类对象,其第一个元素是一个值 将用作属性键,其第二个元素是值 与该属性键关联。


使用方法:

您甚至不需要知道可迭代对象的细节就可以使用Object.fromEntries() 方法。您始终可以在以下对象上使用该方法:

内部/嵌套数组有 2 个元素的 2 维数组 地图

这是一个例子:

// map example:
const map = new Map([ ['hi', 'there'], ['foo', 2] ]);
const objFromMap = Object.fromEntries(map);
console.log(objFromMap); //  hi: "there", foo: 2 

// array example:
const array = [ ['0', '00'], ['1', '11'], ['2', '22'] ];
const objFromArray = Object.fromEntries(array);
console.log(objFromArray); //  0: "00", 1: "11", 2: "22" 

注意,浏览器兼容性!

在撰写本文时(2019 年 12 月),此方法相对较新,并非所有浏览器都实现。为了使用此方法并确保您的 JS 代码可以在所有浏览器中运行,您可能必须将您的代码转换为早期版本的 JS。

【讨论】:

像这样,但让我们给它一些时间:)【参考方案7】:
const sampleArr = ['foo', 'bar', 'baz', 42];
const _chunk = (arr, chunkSize, chunks = []) => 
  while (arr.length) 
    chunks = [...chunks, arr.splice(0, chunkSize)];
  
  return chunks;
; //splice array to chunks

const arr = _chunk(sampleArr, 2);
const entries = new Map([...arr]);

const obj = Object.fromEntries(entries);

console.log(obj)

// 预期输出:Object foo: "bar", baz: 42

【讨论】:

以上是关于如何从键值对数组创建对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何从键值对列表中创建 Spark Row

SQL - 从键值对中提取值到数组

从键数组和值数组创建对象

javascript中数组取值的问题,如何取出键值对中的值?

通过数组迭代设置对象键值对

RestKit 对象映射:如何从键值映射到新对象/关系?