簡體   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