Nullen zwischen Elementen in der Liste hinzufügen?


8

Ich versuche, eine Liste in haskell so zu ändern, dass zwischen jedem Element 0 steht. Wenn wir eine erste Liste haben, [1..20]würde ich sie gerne ändern[1,0,2,0,3..20]

Was ich mir überlegt habe, ist, für jede Funktion eine Karte zu verwenden, ein Element zu extrahieren und es dann zur Liste hinzuzufügen und zu verwenden ++[0], aber nicht sicher, ob dies der richtige Ansatz ist oder nicht. Habe noch Haskell gelernt, könnte also Fehler haben.

Mein Code:

x = map classify[1..20] 

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


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

Antworten:



8

Sie können dies nicht mit tun map. Eine der grundlegenden Eigenschaften von mapist, dass seine Ausgabe immer genau so viele Elemente enthält wie seine Eingabe, da jedes Ausgabeelement einer Eingabe entspricht und umgekehrt.

Es gibt jedoch ein verwandtes Tool mit der erforderlichen Leistung:

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

Auf diese Weise kann jedes Eingabeelement null oder mehr Ausgabeelemente erzeugen. Sie können dies verwenden, um die gewünschte Funktion zu erstellen:

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]

Oder eine präzisere Definition von between:

between sep = drop 1 . concatMap ((sep :) . pure)

4

Mit einfachem Mustervergleich sollte es sein:

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

Wenn Sie mapdies lösen möchten , können Sie Folgendes tun:

Haben Sie eine Funktion, die ein int erhält und 2 Elementlisten mit int und Null zurückgibt:

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

Dann können Sie map mit dieser Funktion aufrufen:

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

Sie werden feststellen, dass es sich um eine verschachtelte Liste handelt. So mapfunktioniert es. Wir brauchen eine Möglichkeit, die innere Liste zu einer einzigen Liste zusammenzufassen. Diesen Fall verwenden wirfoldl

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

In diesem Fall funktioniert Foldl also so, dass es eine Kombinationsfunktion, einen Anfangswert und die zu kombinierende Liste akzeptiert.

Da wir die erste 0 nicht brauchen, können wir sie fallen lassen:

dropFirst :: [Int] -> [Int]
dropFirst list = case list of
  x:xs -> xs
  [] -> []

Endgültiger Code:

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 (++) []ist ein bisschen komisch. Warum nicht einfach darauf zeigen concat?
Amalloy

1
@amalloy Ja, das ist es. Es ist nur so, dass die concatImplementierung selbst auch irgendeine Art von verwendet fold. Ich denke, die Verwendung foldlwürde anderen helfen, es ein bisschen tiefer zu verstehen.
Rinne Hmm

1
concatwird foldreher mit als implementiert foldl. Verstehst du, warum das eigentlich wichtig ist?
Feuer

Ich verstehe das Thema von foldmir nicht ganz . Es gibt ein ganzes Wiki zu diesem Thema. Mein einfaches Verständnis ist, dass dies foldrfür faule unendliche Listen viel besser ist und foldloder foldl'(strenge Version) für allgemeine Anwendungsfälle besser ist.
Rinne Hmm

2

Wir können hier ein foldrMuster verwenden, bei dem wir jedem Element in der ursprünglichen Liste Folgendes voranstellen 0:

addZeros :: Num a => [a] -> [a]
addZeros [] = []
addZeros (x:xs) = x : foldr (((0 :) .) . (:)) [] xs

2

Wenn Sie nicht verwenden möchten intersperse, können Sie Ihre eigenen schreiben.

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

Wenn Sie möchten, können Sie ApplicativeOperationen verwenden:

import Control.Applicative

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

Dies ist im Grunde die Definition in Data.Sequence.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.