Prosedur umum berarti kita tidak perlu menulis ulang kompleksitas setiap kali kita perlu memanfaatkan perilaku tertentu.
concatMap(atau flatMap) persis apa yang kita butuhkan dalam situasi ini.
// concat :: ([a],[a]) -> [a]
const concat = (xs,ys) =>
xs.concat (ys)
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = f => xs =>
xs.map(f).reduce(concat, [])
// id :: a -> a
const id = x =>
x
// flatten :: [[a]] -> [a]
const flatten =
concatMap (id)
// your sample data
const data =
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
console.log (flatten (data))
tinjauan ke masa depan
Dan ya, Anda menebaknya dengan benar, itu hanya meratakan satu tingkat, yang persis bagaimana seharusnya bekerja
Bayangkan beberapa kumpulan data seperti ini
// Player :: (String, Number) -> Player
const Player = (name,number) =>
[ name, number ]
// team :: ( . Player) -> Team
const Team = (...players) =>
players
// Game :: (Team, Team) -> Game
const Game = (teamA, teamB) =>
[ teamA, teamB ]
// sample data
const teamA =
Team (Player ('bob', 5), Player ('alice', 6))
const teamB =
Team (Player ('ricky', 4), Player ('julian', 2))
const game =
Game (teamA, teamB)
console.log (game)
// [ [ [ 'bob', 5 ], [ 'alice', 6 ] ],
// [ [ 'ricky', 4 ], [ 'julian', 2 ] ] ]
Oke, sekarang katakan kita ingin mencetak daftar yang menunjukkan semua pemain yang akan berpartisipasi dalam game...
const gamePlayers = game =>
flatten (game)
gamePlayers (game)
// => [ [ 'bob', 5 ], [ 'alice', 6 ], [ 'ricky', 4 ], [ 'julian', 2 ] ]
Jika flattenprosedur kami juga meratakan susunan bersarang, kami akan berakhir dengan hasil sampah ini ...
const gamePlayers = game =>
badGenericFlatten(game)
gamePlayers (game)
// => [ 'bob', 5, 'alice', 6, 'ricky', 4, 'julian', 2 ]
berguling dalam, sayang
Itu bukan untuk mengatakan kadang-kadang Anda tidak ingin meratakan array bersarang, - hanya itu yang seharusnya tidak menjadi perilaku default.
Kita dapat membuat deepFlattenprosedur dengan mudah ...
// concat :: ([a],[a]) -> [a]
const concat = (xs,ys) =>
xs.concat (ys)
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = f => xs =>
xs.map(f).reduce(concat, [])
// id :: a -> a
const id = x =>
x
// flatten :: [[a]] -> [a]
const flatten =
concatMap (id)
// deepFlatten :: [[a]] -> [a]
const deepFlatten =
concatMap (x =>
Array.isArray (x) ? deepFlatten (x) : x)
// your sample data
const data =
[0, [1, [2, [3, [4, 5], 6]]], [7, [8]], 9]
console.log (flatten (data))
// [ 0, 1, [ 2, [ 3, [ 4, 5 ], 6 ] ], 7, [ 8 ], 9 ]
console.log (deepFlatten (data))
// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Sana. Sekarang Anda memiliki alat untuk setiap pekerjaan - satu untuk meremas satu tingkat sarang flatten,, dan satu untuk melenyapkan semua sarangdeepFlatten .
Mungkin Anda bisa menyebutnya obliterateatau nukejika Anda tidak suka namanya deepFlatten.
Jangan beralih dua kali!
Tentu saja implementasi di atas pintar dan ringkas, tetapi menggunakan .mapdiikuti oleh panggilan untuk.reduce berarti kita benar-benar melakukan lebih banyak iterasi daripada yang diperlukan
Menggunakan kombinator terpercaya saya menelepon mapReducemembantu menjaga iterasi ke minium; dibutuhkan fungsi pemetaan m :: a -> b, fungsi pereduksi r :: (b,a) ->bdan mengembalikan fungsi pereduksi baru - kombinator ini adalah jantung dari transduser ; jika Anda tertarik, saya sudah menulis jawaban lain tentang mereka
// mapReduce = (a -> b, (b,a) -> b, (b,a) -> b)
const mapReduce = (m,r) =>
(acc,x) => r (acc, m (x))
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = f => xs =>
xs.reduce (mapReduce (f, concat), [])
// concat :: ([a],[a]) -> [a]
const concat = (xs,ys) =>
xs.concat (ys)
// id :: a -> a
const id = x =>
x
// flatten :: [[a]] -> [a]
const flatten =
concatMap (id)
// deepFlatten :: [[a]] -> [a]
const deepFlatten =
concatMap (x =>
Array.isArray (x) ? deepFlatten (x) : x)
// your sample data
const data =
[ [ [ 1, 2 ],
[ 3, 4 ] ],
[ [ 5, 6 ],
[ 7, 8 ] ] ]
console.log (flatten (data))
// [ [ 1. 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ] ]
console.log (deepFlatten (data))
// [ 1, 2, 3, 4, 5, 6, 7, 8 ]