haskell - ¿Agregar ceros entre elementos en la lista?
(6)
Aquí podemos hacer uso de un patrón
foldr
donde para cada elemento en la lista original, lo anteponemos con un
0
:
addZeros :: Num a => [a] -> [a]
addZeros [] = []
addZeros (x:xs) = x : foldr (((0 :) .) . (:)) [] xs
Estoy tratando de cambiar una lista en haskell para incluir 0 entre cada elemento.
Si tenemos la lista inicial
[1..20]
, me gustaría cambiarla a
[1,0,2,0,3..20]
Lo que pensé hacer es usar el mapa en cada función, extraer el elemento y luego agregarlo a la lista y usar
++[0]
, pero no estoy seguro de si este es el enfoque correcto o no.
Todavía estoy aprendiendo haskell, por lo que podría tener errores.
Mi código:
x = map classify[1..20]
classify :: Int -> Int
addingFunction 0 [Int]
addingFunction :: Int -> [a] -> [a]
addingFunction x xs = [a] ++ x ++ xs
Con una coincidencia de patrones simple, debería ser:
addingFunction n [] = []
addingFunction n [x] = [x]
addingFunction n (x:xs) = x: n : (addingFunction n xs)
addingFunction 0 [1..20]
=> [1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,16,0,17,0,18,0,19,0,20]
No puedes hacer esto con el
map
.
Una de las propiedades fundamentales del
map
es que su salida siempre tendrá exactamente tantos elementos como su entrada, porque cada elemento de salida corresponde a una entrada, y viceversa.
Sin embargo, hay una herramienta relacionada con la potencia necesaria:
concatMap :: (a -> [b]) -> [a] -> [b]
De esta manera, cada elemento de entrada puede producir cero o más elementos de salida. Puede usar esto para construir la función que desea:
between :: a -> [a] -> [a]
sep `between` xs = drop 1 . concatMap insert $ xs
where insert x = [sep, x]
0 `between` [1..10]
[1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10]
O una definición más concisa de
between
:
between sep = drop 1 . concatMap ((sep :) . pure)
Si desea utilizar el
map
para resolver esto, puede hacer algo como esto:
Tenga una función que obtenga un int y devuelva una lista de 2 elementos con int y cero:
addZero :: List
addZero a = [0, a]
Entonces puede llamar al mapa con esta función:
x = map addZero [1..20] -- this will return [[0,1], [0, 2] ...]
Notarás que es una lista anidada.
Así es como funciona el
map
.
Necesitamos una forma de combinar la lista interna en una sola lista.
Este caso usamos
foldl
combineList :: [[Int]] -> [Int]
combineList list = foldl (++) [] list
-- [] ++ [0, 1] ++ [0, 2] ...
Entonces, la forma en que foldl funciona en este caso es que acepta una función de combinación, un valor inicial y la lista para combinar.
Como no necesitamos el primer 0, podemos soltarlo:
dropFirst :: [Int] -> [Int]
dropFirst list = case list of
x:xs -> xs
[] -> []
Código final:
x = dropFirst $ combineList $ map addZero [1..20]
addZero :: Int -> [Int]
addZero a = [0, a]
combineList :: [[Int]] -> [Int]
combineList list = foldl (++) [] list
dropFirst :: [Int] -> [Int]
dropFirst list = case list of
x:xs -> xs
[] -> []
Si no quieres usar entre
intersperse
, puedes escribir el tuyo.
intersperse :: a -> [a] -> [a]
intersperse p as = drop 1 [x | a <- as, x <- [p, a]]
Si lo desea, puede usar las operaciones
Applicative
:
import Control.Applicative
intersperse :: a -> [a] -> [a]
intersperse p as = drop 1 $ as <**> [const p, id]
Esta es básicamente la definición utilizada en
Data.Sequence
.
intersperse
está hecho para esto.
Simplemente
import Data.List (intersperse)
, luego
intersperse 0 yourList
.