繁体   English   中英

是否有像 function 这样的 .map 对象? 使用相同的密钥创建一个新的 object

[英]Is there a `.map` like function for objects? To create a new object with the same keys

对于数组,我们可以使用.map方法创建具有相同数组结构(即相同数量的元素)的新 map。

例如。

const array = [2, 4, 6]; 
const newArray = array.map(v => v *2); //[4, 8, 12]; 

我相信在函数式编程中,这使得数组 object 成为所谓的functor

对于对象,我想做类似的事情——我想创建一个新的 object,它具有与原始 object 相同的结构(相同的键)以及相同的功能等。

例如。

const obj = {
    foo: 2, 
    bar: 4, 
    biz: 6
}; 

const newObj = obj.map(v => v *2); // {foo: 4, bar: 8, biz: 12}

我目前这样做的方式是使用Object.entries.reduce

 const obj = { foo: 2, bar: 4, biz: 6 }; const newObj = Object.entries(obj).reduce((acc,cur) => { return {...acc, [cur[0]]: cur[1] * 2 } }, {}); console.log(newObj);

我想知道 - 目前是否有一种 object 方法可以让我做到这一点,我错过了? 还是建议增加一个?

对象没有原生的 map,但可以轻松制作。 我认为条目是最简单的。

 const obj = { foo: 2, bar: 4, biz: 6 } const objMap = (obj, fn) => Object.fromEntries( Object.entries(obj).map( ([k, v], i) => [k, fn(v, k, i)] ) ) console.log( objMap(obj, v => v * 2), objMap(obj, (v, k) => `${k}-${v}`), objMap(obj, (v, _, i) => v * i) )

对象的map function 很容易定义。

 Object.defineProperty(Object.prototype, "map", { value(mapping) { const oldEntries = Object.entries(this); const newEntries = oldEntries.map(([key, val]) => [key, mapping(val)]); return Object.fromEntries(newEntries); } }); const obj = { foo: 2, bar: 4, baz: 6 }; const result = obj.map(x => 2 * x); console.log(result);

请注意,这与 kornieff 的objMap function 不同,因为映射 function 无法访问或更改密钥。 因此,它是对象的Functor类型 class 的正确实现。


作为奖励,让我们为对象实现一些其他有用的类型类。 一、 Representable型class。

 Object.tabulate = table => new Proxy({}, { get: (_, key) => table(key) }); const object = Object.tabulate(key => { if (key === "foo") return 10; if (key === "bar") return 20; return 30; }); console.log(object.foo); // 10 console.log(object.bar); // 20 console.log(object.baz); // 30

tabulate function 可用于定义各种有用的类型类,例如MonadComonad 例如,让我们实现Distributive类型 class。 我将把其他类型类的实现留给读者作为练习。

 Object.tabulate = table => new Proxy({}, { get: (_, key) => table(key) }); const distribute = functor => Object.tabulate(key => functor.map(object => object[key])); const result1 = distribute([ { foo: 10, bar: 20 }, { foo: 30, bar: 40 } ]); console.log(result1.foo); // [ 10, 30 ] console.log(result1.bar); // [ 20, 40 ] Object.defineProperty(Object.prototype, "map", { value(mapping) { const oldEntries = Object.entries(this); const newEntries = oldEntries.map(([key, val]) => [key, mapping(val)]); return Object.fromEntries(newEntries); } }); const result2 = distribute({ a: { foo: 10, bar: 20 }, b: { foo: 30, bar: 40 } }); console.log(result2.foo); // { a: 10, b: 30 } console.log(result2.bar); // { a: 20, b: 40 }

请注意, distribute期望 object 具有map方法,这就是我们在 Z497031794151AAC3B5443 上定义map方法的Object.prototype 然而,我们可以使用Yoneda引理来绕过这个限制。

一种方法:

 const obj = { foo: 2, bar: 4, biz: 6 }; const x = Object.keys(obj).map(o => { return {[o]: obj[o] * 2} }) console.log(JSON.stringify(x, null, 2))

使用.reduce()的另一种方法是这样的,使用解构来更容易阅读(我认为)

 const obj = { foo: 2, bar: 4, biz: 6 }; const newObj = Object.entries(obj).reduce( (acc, [key, value]) => ({...acc, [key]: value * 2}), {} ); console.log(newObj)

如果您想在代码中尝试一些功能性 API,那么您可以考虑使用功能性库(例如 Ramda),

它不仅介绍了对象(地图)的函子 api,还介绍了其他很酷的东西!

 const input = { a: 1, b: 44, c: 77 }; const doubled = R.map(R.multiply(2), input); console.log( `doubling input`, doubled, ); // and a lot more... const odds = R.filter(R.modulo(R.__, 2), input); console.log( `filtering odds only of input`, odds, );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>

您可以使用 lodash 的function mapValues

常量数组 = [2, 4, 6];

_.mapValues(数组,v => v * 2)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM