¿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 

Respuestas:



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)

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]

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
  [] -> []

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

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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.