Добавлять нули между элементами в списке? - PullRequest
8 голосов
/ 18 октября 2019

Я пытаюсь изменить список в haskell, чтобы включить 0 между каждым элементом. Если у нас есть начальный список [1..20], то я хотел бы изменить его на [1,0,2,0,3..20]

. Что я думал о том, чтобы сделать это на самом деле, использовать карту в каждой функции, извлечь элемент, затем добавить его в список и использовать ++[0]к этому, но не уверен, если это правильный подход или нет. Все еще изучаю haskell, поэтому могут быть ошибки.

Мой код:

x = map classify[1..20] 

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


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

Ответы [ 6 ]

10 голосов
/ 18 октября 2019

intersperse сделано для этого. Просто import Data.List (intersperse), затем intersperse 0 yourList.

8 голосов
/ 18 октября 2019

Вы не можете сделать это с map. Одним из фундаментальных свойств map является то, что на его выходе всегда будет ровно столько же элементов, сколько на его входе, поскольку каждый выходной элемент соответствует одному входу, и наоборот.

Существует связанный инструмент снеобходимая мощность, однако:

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

Таким образом, каждый элемент ввода может производить ноль или более элементов вывода. Вы можете использовать это для построения желаемой функции:

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]

Или более краткое определение between:

between sep = drop 1 . concatMap ((sep :) . pure)
4 голосов
/ 18 октября 2019

При простом сопоставлении с образцом оно должно быть:

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 голосов
/ 18 октября 2019

Если вы хотите использовать map для решения этой проблемы, вы можете сделать что-то вроде этого:

Иметь функцию, которая получает int и возвращает список из 2 элементов с int и нулем:

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

Затем вы можете вызвать карту с помощью этой функции:

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

Вы заметите, что это вложенный список. Так работает map. Нам нужен способ объединить внутренний список в один список. В этом случае мы используем foldl

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

Таким образом, в этом случае работа foldl заключается в том, что он принимает функцию объединения, начальное значение и список для объединения.

Поскольку первые 0 нам не нужны, мы можем отбросить их:

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

Окончательный код:

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

2 голосов
/ 18 октября 2019

Если вы не хотите использовать intersperse, вы можете написать свой собственный.

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

Если хотите, вы можете использовать Applicative операций:

import Control.Applicative

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

Это в основном определение, используемое в Data.Sequence.

2 голосов
/ 18 октября 2019

Здесь мы можем использовать шаблон foldr, где для каждого элемента в исходном списке мы добавляем 0:

addZeros :: Num a => [a] -> [a]
addZeros [] = []
addZeros (x:xs) = x : foldr (((0 :) .) . (:)) [] xs
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...