Generische Prozeduren bedeuten, dass wir die Komplexität nicht jedes Mal neu schreiben müssen, wenn wir ein bestimmtes Verhalten verwenden müssen.
concatMap
(oder flatMap
) ist genau das, was wir in dieser Situation brauchen.
// 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))
Voraussicht
Und ja, Sie haben es richtig erraten, es glättet nur eine Ebene, genau so sollte es funktionieren
Stellen Sie sich einen solchen Datensatz vor
// 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 ] ] ]
Ok, jetzt sagen wir, wir möchten eine Liste drucken, in der alle Spieler aufgeführt sind, die teilnehmen werden game
.
const gamePlayers = game =>
flatten (game)
gamePlayers (game)
// => [ [ 'bob', 5 ], [ 'alice', 6 ], [ 'ricky', 4 ], [ 'julian', 2 ] ]
Wenn unsere flatten
Prozedur auch verschachtelte Arrays reduzieren würde, würden wir dieses Müllergebnis erhalten ...
const gamePlayers = game =>
badGenericFlatten(game)
gamePlayers (game)
// => [ 'bob', 5, 'alice', 6, 'ricky', 4, 'julian', 2 ]
rollt tief, Baby
Das heißt nicht, dass Sie manchmal auch nicht verschachtelte Arrays reduzieren möchten - nur das sollte nicht das Standardverhalten sein.
Wir können deepFlatten
mit Leichtigkeit ein Verfahren durchführen ...
// 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 ]
Dort. Jetzt haben Sie für jeden Job ein Werkzeug - eines zum Quetschen einer Verschachtelungsebene flatten
und eines zum Löschen aller Verschachtelungen deepFlatten
.
Vielleicht kannst du es nennen obliterate
oder nuke
wenn dir der Name nicht gefällt deepFlatten
.
Nicht zweimal iterieren!
Natürlich sind die oben genannten Implementierungen clever und prägnant, aber .map
wenn .reduce
wir einen gefolgt von einem Aufruf von verwenden, bedeutet dies, dass wir tatsächlich mehr Iterationen als nötig durchführen
Die Verwendung eines vertrauenswürdigen Kombinators, den ich anrufe, mapReduce
hilft dabei, die Iterationen auf ein Minimum zu beschränken. Es übernimmt eine Abbildungsfunktion m :: a -> b
, eine Reduktionsfunktion r :: (b,a) ->b
und gibt eine neue Reduktionsfunktion zurück - dieser Kombinator ist das Herzstück der Wandler . Wenn Sie interessiert sind, habe ich andere Antworten darüber geschrieben
// 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 ]