ChatGPT解决这个技术问题 Extra ChatGPT

将对象数组转换为哈希映射,由对象的属性值索引

用例

用例是根据提供的字符串或函数将对象数组转换为哈希映射,以评估并用作哈希映射中的键,并将值用作对象本身。使用它的常见情况是将对象数组转换为对象的哈希映射。

代码

以下是 JavaScript 中的一个小片段,用于将对象数组转换为哈希映射,由 object 的属性值索引。您可以提供一个函数来动态评估哈希映射的键(运行时)。

function isFunction(func) {
    return Object.prototype.toString.call(func) === '[object Function]';
}

/**
 * This function converts an array to hash map
 * @param {String | function} key describes the key to be evaluated in each object to use as key for hashmap
 * @returns Object
 * @Example 
 *      [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap("id")
 *      Returns :- Object {123: Object, 345: Object}
 *
 *      [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap(function(obj){return obj.id+1})
 *      Returns :- Object {124: Object, 346: Object}
 */
Array.prototype.toHashMap = function(key) {
    var _hashMap = {}, getKey = isFunction(key)?key: function(_obj){return _obj[key];};
    this.forEach(function (obj){
        _hashMap[getKey(obj)] = obj;
    });
    return _hashMap;
};

您可以在此处找到要点:Converts Array of Objects to HashMap

您可以使用 JavaScript Map 而不是 Object。查看stackoverflow.com/a/54246603/5042169

v
vsync

这对于 Array.prototype.reduce 来说相当简单:

var arr = [ { key: 'foo', val: 'bar' }, { key: 'hello', val: 'world' } ]; var result = arr.reduce(function(map, obj) { map[obj.key] = obj.val; return map; }, {});控制台.log(结果); // { foo:'bar', hello:'world' }

注意: Array.prototype.reduce() 是 IE9+,因此如果您需要支持旧版浏览器,则需要对其进行 polyfill。


result = arr.reduce((map, obj) => (map[obj.key] = obj.val, map), {}); 对于 ES6 单行爱好者:D
@Mtz 对于 ES6 单线爱好者来说,mateuscb 下面的回复更小更干净:result = new Map(arr.map(obj => [obj.key, obj.val]));。最重要的是,它非常清楚正在返回地图。
@RyanShillington,我们在此处处于答案的上下文中,即 jmar777 提出的 Array.prototype.reduceMap 确实更短,但它是另一回事。我一直在与最初的意图保持一致。请记住,这不是一个论坛,您可能想了解更多关于 SO Q/A 结构的信息。
@Mtz 够公平的。
这不是所要求的,恕我直言。显示的数组的正确结果是:{ "foo": {key: 'foo', val: 'bar'}, "hello": {key: 'hello', val: 'world'} }。请注意,每个原始元素应完整保留。或使用 Q 的数据:{"345": {id:345, name:"kumar"}, ...}。修复:将代码更改为 map[obj.key] = obj;
R
Ryan Shillington

使用 ES6 Map (pretty well supported),你可以试试这个:

var arr = [ { key: 'foo', val: 'bar' }, { key: 'hello', val: 'world' } ]; var result = new Map(arr.map(i => [i.key, i.val])); // 使用 TypeScript 时,需要指定类型: // var result = arr.map((i): [string, string] => [i.key, i.val]) // 不幸的是 map 不能很好地字符串化.这是数组形式的内容。 console.log("结果是:" + JSON.stringify([...result])); // 映射 {"foo" => "bar", "hello" => "world"}


同样重要的是要注意,要从 Map 中获取某些内容,您需要使用 result.get(keyName) 而不是仅使用 result[keyName]。另请注意,任何对象都可以用作键,而不仅仅是字符串。
另一个 TypeScript 版本如下所示:var result = new Map(arr.map(i => [i.key, i.val] as [string, string]));,有些人可能会觉得更容易理解。注意 as [string, string] 类型转换添加。
PS result 不是 OP 要求的散列。
另一个打字稿版本:var result = new Map<string, string>(arr.map(i => [i.key, i.val]));
@AlexV 这是一种类型断言,应尽可能避免使用。相反,您可以使用 new Map<string, string> 键入地图。
S
Sergey Vyacheslavovich Brunov

您可以使用新的 Object.fromEntries() 方法。

例子:

常量数组 = [ {键:'a',值:'b',冗余:'aaa'},{键:'x',值:'y',冗余:'zzz'}] const hash = Object.fromEntries ( array.map(e => [e.key, e.value]) ) console.log(hash) // {a: b, x: y}


这比最佳答案更具可读性;但是,它将对数组进行两次迭代(一次用于 map 调用,一次用于 Object.fromEntries 调用)。
@knguyen 是的,我猜是的。但在大多数情况下,我猜额外的循环并不重要
s
shuk

使用 ES6 spread + Object.assign:

array = [{key: 'a', value: 'b', redundant: 'aaa'}, {key: 'x', value: 'y', redundant: 'zzz'}]

const hash = Object.assign({}, ...array.map(s => ({[s.key]: s.value})));

console.log(hash) // {a: b, x: y}

完美,正是我需要的;)
const hash = Object.assign({}, ...(<{}>array.map(s => ({[s.key]: s.value})))); 必须进行此更改才能使用打字稿。
需要注意的是,此方法不会导致 Map 而是对象
s
splintor

对于 lodash,这可以使用 keyBy 完成:

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = _.keyBy(arr, o => o.key);

console.log(result);
// Object {foo: Object, hello: Object}

那不是哈希图
P
Pedro Lopes

使用扩展运算符:

const result = arr.reduce(
    (accumulator, target) => ({ ...accumulator, [target.key]: target.val }),
    {});

jsFiddle 上的代码段演示。


我就是因为这个才来的!扩展运算符如何执行与仅分配新键并返回累加器的常规旧方法相反的操作?因为它每次都在创建一个新副本,所以 spread 的表现会很差!
现在你在每次迭代中传播。在减速器中变异应该是安全的。 ``` const result = arr.reduce( (accumulator, target) => { accumulator[target.key]: target.val; return accumulator }, {}); ```
J
Jun711

您可以使用 Array.prototype.reduce() 和实际的 JavaScript Map 而不是仅使用 JavaScript Object

let keyValueObjArray = [
  { key: 'key1', val: 'val1' },
  { key: 'key2', val: 'val2' },
  { key: 'key3', val: 'val3' }
];

let keyValueMap = keyValueObjArray.reduce((mapAccumulator, obj) => {
  // either one of the following syntax works
  // mapAccumulator[obj.key] = obj.val;
  mapAccumulator.set(obj.key, obj.val);

  return mapAccumulator;
}, new Map());

console.log(keyValueMap);
console.log(keyValueMap.size);

地图和对象有什么区别?以前,在 JavaScript 中实现 Map 之前,Object 已被用作 Map,因为它们的结构相似。根据您的用例,如果您需要有序键、需要访问地图的大小或频繁地从地图中添加和删除,则最好使用地图。

引自 MDN document
对象与 Map 相似,因为它们都允许您将键设置为值、检索这些值、删除键以及检测键中是否存储了某些内容。正因为如此(并且因为没有内置的替代品),对象在历史上一直被用作地图;但是,在某些情况下,使用 Map 更可取的重要区别是:

对象的键是字符串和符号,而它们可以是 Map 的任何值,包括函数、对象和任何原语。

Map 中的键是有序的,而添加到对象的键不是。因此,在对其进行迭代时, Map 对象会按插入顺序返回键。

您可以使用 size 属性轻松获取 Map 的大小,而 Object 中的属性数量必须手动确定。

Map 是可迭代的,因此可以直接迭代,而对 Object 进行迭代则需要以某种方式获取其键并对其进行迭代。

一个对象有一个原型,所以如果你不小心,地图中有默认键可能会与你的键发生冲突。从 ES5 开始,这可以通过使用 map = Object.create(null) 绕过,但很少这样做。

在涉及频繁添加和删除密钥对的场景中,Map 可能会表现得更好。


你错过了一个箭头。将 (mapAccumulator, obj) {...} 更改为 (mapAccumulator, obj) => {...}
b
baryo

es2015版本:

const myMap = new Map(objArray.map(obj => [ obj.key, obj.val ]));

K
King Friday

🏆 最糟糕的

list.reduce((obj, item) => ({...obj, [item.name]: item.value}), {})

const list = [ { name: 'abc', value: 123 }, { name: 'xyz', value: 789 }, { name: 'she', value: 'her' }, { name: 'he', value : '他'} ] console.log( list.reduce((obj, item) => ({...obj, [item.name]: item.value}), {}) )


H
Hinek

正如其他海报所解释的,有更好的方法来做到这一点。但如果我想坚持纯 JS 和老式的方式,那么这里是:

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' },
    { key: 'hello', val: 'universe' }
];

var map = {};
for (var i = 0; i < arr.length; i++) {
    var key = arr[i].key;
    var value = arr[i].val;

    if (key in map) {
        map[key].push(value);
    } else {
        map[key] = [value];
    }
}

console.log(map);

是否建议使用 reduce 方法而不是此方法。我觉得用这种方法。它简单易懂,一目了然。
我喜欢这种方法。我认为有时最简单的代码是最好的。现在人们对可变性感到厌烦,但只要它被包含,可变性实际上是非常棒的和高性能的。
我使用它是因为 IE11 不允许使用 Lambda
感谢您发布具有多个相同键的唯一示例,这是我需要处理的情况。我也喜欢这个,因为正如 Anthosh 所说,您实际上可以看到发生了什么。我对改进这个答案的唯一建议是显示输出
T
Tiago Bértolo

如果您想转换为新的 ES6 Map,请执行以下操作:

var kvArray = [['key1', 'value1'], ['key2', 'value2']];
var myMap = new Map(kvArray);

为什么要使用这种类型的地图?这取决于你。看看this


P
Peter

这就是我在 TypeScript 中所做的我有一个小工具库,我在其中放置了这样的东西

export const arrayToHash = (array: any[], id: string = 'id') => 
         array.reduce((obj, item) =>  (obj[item[id]] = item , obj), {})

用法:

const hash = arrayToHash([{id:1,data:'data'},{id:2,data:'data'}])

或者如果您有除“id”以外的标识符

const hash = arrayToHash([{key:1,data:'data'},{key:2,data:'data'}], 'key')

如果您想使用对象作为键,则必须使用 Map 而不是 Object,因为打字稿不允许您使用对象作为键
const normalize = (a,f) => a.reduce((m,o)=>(m[o[f]]=o,m),{});
M
Mor Shemesh

reduce 用法的小改进:

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = arr.reduce((map, obj) => ({
    ...map,
    [obj.key] = obj.val
}), {});

console.log(result);
// { foo: 'bar', hello: 'world' }

它比 other 答案快吗?
@orad 可能不会,因为它会传播累加器并在每次迭代时创建新对象。
T
Tho

使用 lodash

const items = [
    { key: 'foo', value: 'bar' },
    { key: 'hello', value: 'world' }
];

const map = _.fromPairs(items.map(item => [item.key, item.val]));

// OR: if you want to index the whole item by key:
// const map = _.fromPairs(items.map(item => [item.key, item]));

lodash fromPairs 函数让我想起了 zip function in Python

链接到 lodash


R
RyanShao

减少版本似乎不起作用。我跟随。

   let map = {};
    items.forEach(v=>{
      map [v.xxx] = v;
    });

m
markcheeky

使用简单的 Javascript

var createMapFromList = function(objectList, property) {
    var objMap = {};
    objectList.forEach(function(obj) {
      objMap[obj[property]] = obj;
    });
    return objMap;
  };
// objectList - the array  ;  property - property as the key

在这个例子中没有使用 .map(...) 没有意义,因为你没有返回任何东西?在这种情况下,我建议使用 forEach。
N
Nguyễn Anh Tuấn

如果有人感兴趣,我会在 TypeScript 中更清楚地说明。

interface Person {
  id: number;
  name: string;
}
type Result = Map<number, string>

const input: Array<Person> = [
  {
    id: 123,
    name: "naveen"
  },
  {
    id: 345,
    name: "kumar"
  },
];
const convertedToMap: Result = input.reduce(
  (map: Result, person: Person) => {
    map.set(person.id, person.name);
    return map;
  },
  new Map()
);

K
Kamil Kiełczewski

尝试

let toHashMap = (a,f) => a.reduce((a,c)=> (a[f(c)]=c,a),{});

让 arr=[ {id:123, name:'naveen'}, {id:345, name:"kumar"} ];让 fkey = o => o.id; // 将对象转换为字符串 (key) 的函数 let toHashMap = (a,f) => a.reduce((a,c)=> (a[f(c)]=c,a),{}); console.log(toHashMap(arr,fkey)); // 不建议添加到原型: // // Array.prototype.toHashMap = function(f) { return toHashMap(this,f) }; // console.log(arr.toHashMap(fkey));


Y
Yada

对我来说,我不喜欢使用任何 mapreduce,而是坚持使用简单的 for 循环。

const array = [
   {key: 'a', value: 'b', redundant: 'aaa'},
   {key: 'x', value: 'y', redundant: 'zzz'}
]

const hash = {};

for (const item of array) {
    hash[item.key] = item;
}

console.log(hash);

我同意@Yada。易于阅读和直截了当的代码对于理智来说是更可取的。
我是 2 年前开始的新反应 MERN 开发人员,我被所有这些减少、过滤、映射的东西淹没了……虽然我正在学习它,但过滤器对我来说是最困惑的。
J
Jacman

像这样映射数组:

const items = [
{ key: 'foo', value: 'bar' },
{ key: 'hello', value: 'world' }
];

let [k,v] = items.map(item => [item.key, item.value])   
console.log([k,v]) 

//Output: [ [ 'foo', 'bar' ], [ 'hello', 'world' ] ]

N
Naveen I

以下是我在 javascript 中创建的小片段,用于将对象数组转换为哈希映射,由对象的属性值索引。您可以提供一个函数来动态评估哈希映射的键(运行时)。

function isFunction(func){
    return Object.prototype.toString.call(func) === '[object Function]';
}

/**
 * This function converts an array to hash map
 * @param {String | function} key describes the key to be evaluated in each object to use as key for hasmap
 * @returns Object
 * @Example 
 *      [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap("id")
        Returns :- Object {123: Object, 345: Object}

        [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap(function(obj){return obj.id+1})
        Returns :- Object {124: Object, 346: Object}
 */
Array.prototype.toHashMap = function(key){
    var _hashMap = {}, getKey = isFunction(key)?key: function(_obj){return _obj[key];};
    this.forEach(function (obj){
        _hashMap[getKey(obj)] = obj;
    });
    return _hashMap;
};

您可以在这里找到要点:https://gist.github.com/naveen-ithappu/c7cd5026f6002131c1fa


请,请,请不要推荐扩展 Array.prototype
啊,我明白了。我最初认为这是一个建议的答案:)