![](/img/trans.png)
[英]How to filter an array of objects by the element inside an inner array - Functional Programming Javascript
[英]How to push an element to an array inside a Map using functional programming in TypeScript/JavaScript?
我剛剛開始從 OOP 背景到學習 FP,以及從編寫普通 TypeScript(命令式?)遷移到功能性 TypeScript 代碼的過程。 不幸的是,我已經在努力弄清楚如何將其更改為功能代碼:
const foos: Map<
string,
Bar[]
> = new Map();
export const addBar = (
key: string,
bar: Bar
) => {
const foo = foos.get(key);
if (foo) {
foo.push(bar);
} else {
foos.set(key, [bar]);
}
};
我了解 .map .filter .concat 可以如何用於數組,但是如何處理包含數組的 Map?
關於 foos Map 它我猜 Map 本身需要只讀,還有里面的 Bar 數組,所以 .set .push 是不可能的。 但是如果我不能在 Map 上調用 .set 因為它是只讀的,那么使用 Map 還是我應該只使用一個對象是否有意義?
如果沒有可變性,如何將元素推送到 Map 值內的數組(或者,如果鍵不存在,則使用該數組創建一個新映射,就像上面的代碼一樣)?
並且這種性能是否足夠高,因為我需要每隔幾秒向數組添加一個新元素,每次發生更改時復制整個地圖(包括其許多數組)的不可變方式的性能不會比我差很多嗎?剛剛像通常那樣改變了數組?
您根本無法使用本機Map
因為它僅提供命令式接口。
你可以找到一個開源庫,比如流行的 ImmutableJS。
或者您可以編寫自己的持久(不可變)數據結構。 基本要求是您的數據結構提供的操作不會修改輸入。 相反,每個操作都會返回一個新的數據結構 -
const PersistentMap =
{ create: () =>
({})
, set: (t = {}, key, value) =>
({ ...t, [key]: value }) // <-- immutable operation
}
我們先看一個empty
map,一個set
操作的結果,然后確定這個empty
map沒有被修改——
const empty =
PersistentMap.create()
console.log
( empty
, PersistentMap.set(empty, "hello", "world")
, empty
)
// {}
// { hello: "world" }
// {}
現在讓我們看看一個新的中間狀態m1
。 每次我們看到set
返回一個新的持久化映射並且不會修改輸入——
const m1 =
PersistentMap.set(empty, "hello", "earth")
console.log
( m1
, PersistentMap.set(m1, "stay", "inside")
, m1
)
// { hello: "earth" }
// { hello: "earth", stay: "inside" }
// { hello: "earth" }
現在回答您的問題,我們可以向我們的PersitentMap
添加push
操作 - 我們只需要確保我們不修改輸入。 這是一種可能的實現 -
const PersistentMap =
{ // ...
, push: (t = {}, key, value) =>
PersistentMap.set // <-- immutable operation
( t
, key
, Array.isArray(t[key])
? [ ...t[key], value ] // <-- immutable operation
: [ value ]
)
}
我們在下面看到push
行動。 請注意,結果更改了m2
和empty
-
const m2 =
PersistentMap.push(empty, "fruits", "apple")
console.log
( m2
, PersistentMap.push(m2, "fruits", "peach")
, m2
, empty
)
// { fruits: [ "apple" ] }
// { fruits: [ "apple", "peach" ] }
// { fruits: [ "apple" ] }
// {}
展開下面的代碼段以在您自己的瀏覽器中驗證結果
const PersistentMap = { create: () => ({}) , set: (t = {}, key, value) => ({ ...t, [key]: value }) , push: (t = {}, key, value) => PersistentMap.set ( t , key , Array.isArray(t[key]) ? [ ...t[key], value ] : [ value ] ) } const empty = PersistentMap.create() console.log ( empty , PersistentMap.set(empty, "hello", "world") , empty ) // {} // { hello: "world" } // {} const m1 = PersistentMap.set(empty, "hello", "earth") console.log ( m1 , PersistentMap.set(m1, "stay", "inside") , m1 ) // { hello: "earth" } // { hello: "earth", stay: "inside" } // { hello: "earth" } const m2 = PersistentMap.push(empty, "fruits", "apple") console.log ( m2 , PersistentMap.push(m2, "fruits", "peach") , m2 , empty ) // { fruits: [ "apple" ] } // { fruits: [ "apple", "peach" ] } // { fruits: [ "apple" ] } // {}
我認為這取決於您想要實現的目標。 如果您希望您的代碼可測試,FP 並不總是意味着只編寫函數,您仍然可以使用類,但是如果您有一段復雜的代碼要單獨測試,則可以導出該代碼段進行測試,並且它看起來像這樣:
// types.ts
type FooDis = Record<string, object[]>;
// addBarToFoos.ts
export const addBarToFoos = (foos: FooDis) => (key: string, bar: object): FooDis {
foos = {
...foos,
[key]: [
...foos[key],
bar
]
};
return foos;
}
// FooClass.ts
export class FooClass {
private foos: FooDis = {};
addBar(key: string, bar: object) {
this.foos = addBarToFoos(this.foos)(key, bar);
}
}
這樣,“復雜”方法無需外部依賴即可單獨測試,並且您有一個使用該方法的實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.