Adicionando zeros entre elementos na lista?

8

Estou tentando alterar uma lista no haskell para incluir 0 entre cada elemento. Se tivermos uma lista inicial [1..20], gostaria de alterá-la para[1,0,2,0,3..20]

O que eu pensei em fazer é realmente usar o mapa em todas as funções, extrair o elemento e adicioná-lo à lista e usá ++[0]-lo, mas não tenho certeza se essa é a abordagem correta ou não. Ainda aprendendo haskell, pode haver erros.

Meu código:

x = map classify[1..20] 

classify :: Int -> Int 
addingFunction 0 [Int]


addingFunction :: Int -> [a] -> [a]
addingFunction x xs = [a] ++ x ++ xs 
STOPIMACODER
fonte

Respostas:

10

intersperseé feito para isso. Apenas import Data.List (intersperse)então intersperse 0 yourList.

Joseph Sible-Restabelecer Monica
fonte
Sim que funciona também, mas meio que queria cavar fundo para compreender Haskell mais
STOPIMACODER
8

Você não pode fazer isso com map. Uma das propriedades fundamentais de mapé que sua saída sempre terá exatamente tantos itens quanto sua entrada, porque cada elemento de saída corresponde a uma entrada e vice-versa.

Existe uma ferramenta relacionada com a energia necessária, no entanto:

concatMap :: (a -> [b]) -> [a] -> [b]

Dessa forma, cada item de entrada pode produzir zero ou mais itens de saída. Você pode usar isso para criar a função desejada:

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]

Ou uma definição mais concisa de between:

between sep = drop 1 . concatMap ((sep :) . pure)
amalloy
fonte
4

Com uma correspondência simples de padrões, deve 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
fonte
3

Se você deseja usar mappara resolver isso, pode fazer algo assim:

Tem uma função que obtém uma lista int e retorna 2 elementos com int e zero:

addZero :: List
addZero a = [0, a]

Então você pode chamar o mapa com esta função:

x = map addZero [1..20] -- this will return [[0,1], [0, 2] ...] 

Você notará que é uma lista aninhada. É assim que mapfunciona. Precisamos de uma maneira de combinar a lista interna em apenas uma lista. Neste caso, usamosfoldl

combineList :: [[Int]] -> [Int]
combineList list = foldl' (++) [] list 
-- [] ++ [0, 1] ++ [0, 2] ... 

Portanto, a maneira como foldl funciona nesse caso é que ele aceita uma função de combinação, valor inicial e a lista a combinar.

Como não precisamos do primeiro 0, podemos eliminá-lo:

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
fonte
1
foldl (++) []é um pouco estranho. Por que não apenas apontar concat?
amalloy
1
@amalloy Sim, é. É que a concatprópria implementação também usa algum tipo de fold. Então, acho que usar foldlajudaria outros a entender um pouco mais a fundo.
Rinne Hmm
1
concaté implementado usando em foldrvez de foldl. Você entende por que isso é realmente importante?
Dfeuer 18/10/19
Eu não entendo completamente o assunto de foldmim mesmo. Existe um wiki inteiro relacionado a esse assunto. Meu entendimento simples é que foldré muito melhor para lista infinita lenta e foldlou foldl'(versão estrita) é melhor para caso de uso geral.
Rinne Hmm
2

Aqui, podemos usar um foldrpadrão em que, para cada elemento da lista original, o anexamos com um 0:

addZeros :: Num a => [a] -> [a]
addZeros [] = []
addZeros (x:xs) = x : foldr (((0 :) .) . (:)) [] xs
Willem Van Onsem
fonte
2

Se você não quiser usar intersperse, pode escrever o seu.

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

Se desejar, você pode usar as Applicativeoperações:

import Control.Applicative

intersperse :: a -> [a] -> [a]
intersperse p as = drop 1 $ as <**> [const p, id]

Esta é basicamente a definição usada em Data.Sequence.

dfeuer
fonte