सामान्य प्रक्रियाओं का मतलब है कि हमें किसी विशिष्ट व्यवहार का उपयोग करने के लिए हर बार जटिलता को फिर से लिखना नहीं पड़ता है।
concatMap
(या flatMap
) वास्तव में इस स्थिति में हमें क्या चाहिए।
// 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))
दूरदर्शिता
और हां, आपने इसे सही तरीके से अनुमान लगाया है, यह केवल एक स्तर को समतल करता है, जो कि वास्तव में यह कैसे काम करना चाहिए
कुछ डेटा सेट की कल्पना करें
// 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 ] ] ]
ठीक है, अब कहते हैं कि हम एक रोस्टर प्रिंट करना चाहते हैं जो सभी खिलाड़ियों को दिखाता है game
...
const gamePlayers = game =>
flatten (game)
gamePlayers (game)
// => [ [ 'bob', 5 ], [ 'alice', 6 ], [ 'ricky', 4 ], [ 'julian', 2 ] ]
यदि हमारी flatten
प्रक्रिया नेस्टेड एरेट्स को भी समतल कर दिया है, तो हम इस कचरा परिणाम को समाप्त कर देंगे ...
const gamePlayers = game =>
badGenericFlatten(game)
gamePlayers (game)
// => [ 'bob', 5, 'alice', 6, 'ricky', 4, 'julian', 2 ]
रोलिन डीप, बेबी
यह कहना है कि कभी-कभी आप नेस्टेड ऐरे को समतल नहीं करना चाहते हैं, वह भी - केवल यह कि डिफ़ॉल्ट व्यवहार नहीं होना चाहिए।
हम deepFlatten
आसानी के साथ एक प्रक्रिया कर सकते हैं ...
// 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 ]
वहाँ। अब आपके पास प्रत्येक काम के लिए एक उपकरण है - एक घोंसले के शिकार के स्तर को कम करने के flatten
लिए, और सभी घोंसले को खत्म करने के लिए एक हैdeepFlatten
।
शायद आप इसे कॉल कर सकते हैं obliterate
या nuke
यदि आपको नाम पसंद नहीं है deepFlatten
।
दो बार पुनरावृति मत करो!
बेशक उपरोक्त कार्यान्वयन चतुर और संक्षिप्त हैं, लेकिन .map
एक कॉल का उपयोग करके .reduce
इसका मतलब है कि हम वास्तव में आवश्यकता से अधिक पुनरावृत्तियों कर रहे हैं
एक भरोसेमंद कॉम्बीनेटर का उपयोग करके मैं कॉल कर रहा हूं mapReduce
, एक minium को पुनरावृत्तियों को बनाए रखने में मदद करता है; यह एक मैपिंग फ़ंक्शन m :: a -> b
, एक कम करने वाला फ़ंक्शन लेता है r :: (b,a) ->b
और एक नया रिडक्शन फ़ंक्शन देता है - यह कॉम्बिनेटर ट्रांसड्यूसर्स के दिल में है ; यदि आप रुचि रखते हैं, तो मैंने उनके बारे में अन्य उत्तर लिखे हैं
// 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 ]