¿Agregar ceros entre elementos en la lista?

8

Estoy tratando de cambiar una lista en haskell para incluir 0 entre cada elemento. Si tenemos una lista inicial [1..20], me gustaría cambiarla a[1,0,2,0,3..20]

Lo que pensé en hacer es usar el mapa en cada función, extraer el elemento y luego agregarlo a la lista y usarlo ++[0], pero no estoy seguro de si este es el enfoque correcto o no. Todavía estoy aprendiendo Haskell, por lo que podría haber 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 
STODIMACODER
fuente

Respuestas:

10

intersperseestá hecho para esto. Solo import Data.List (intersperse)entonces intersperse 0 yourList.

Joseph Sible-Reinstate a Monica
fuente
Sí, eso también funciona, pero un poco quería profundizar para comprender más a Haskell
STOPIMACODER
8

No puedes hacer esto con map. Una de las propiedades fundamentales de mapes 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)
amalloy
fuente
4

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]
Damián Rafael Lattenero
fuente
3

Si desea utilizar mappara 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 mapfunciona. Necesitamos una forma de combinar la lista interna en una sola lista. Este caso usamosfoldl

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
  [] -> []
Rinne Hmm
fuente
1
foldl (++) []es un poco raro ¿Por qué no solo señalar concat?
amalloy
1
@amalloy Sí, lo es. Es solo que la concatimplementación en sí misma también usa algún tipo de fold. Así que supongo que usar foldlayudaría a otros a entenderlo un poco más profundo.
Rinne Hmm
1
concatse implementa utilizando en foldrlugar de foldl. ¿Entiendes por qué esto es realmente importante?
dfeuer
No entiendo completamente el tema de foldmí mismo. Hay toda una wiki relacionada con este tema. Mi simple comprensión es que foldres mucho mejor para la lista infinita perezosa, y foldlor foldl'(versión estricta) es mejor para el caso de uso general.
Rinne Hmm
2

Aquí podemos hacer uso de un foldrpatrón 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
Willem Van Onsem
fuente
2

Si no desea usar intersperse, puede escribir el suyo.

intersperse :: a -> [a] -> [a]
intersperse p as = drop 1 [x | a <- as, x <- [p, a]]

Si lo desea, puede usar Applicativeoperaciones:

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.

dfeuer
fuente