Thêm số không giữa các yếu tố trong danh sách?


8

Tôi đang cố gắng thay đổi một danh sách trong haskell để bao gồm 0 giữa mọi phần tử. Nếu chúng tôi có danh sách ban đầu [1..20]thì tôi muốn thay đổi nó thành[1,0,2,0,3..20]

Những gì tôi nghĩ về việc thực sự là sử dụng bản đồ trên mọi chức năng, trích xuất phần tử sau đó thêm nó vào danh sách và sử dụng ++[0]nó nhưng không chắc đây có phải là phương pháp phù hợp hay không. Vẫn đang học haskell nên có thể có lỗi.

Mã của tôi:

x = map classify[1..20] 

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


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

Câu trả lời:



8

Bạn không thể làm điều này với map. Một trong những thuộc tính cơ bản của maplà đầu ra của nó sẽ luôn có chính xác nhiều mục như đầu vào của nó, bởi vì mỗi phần tử đầu ra tương ứng với một đầu vào và ngược lại.

Có một công cụ liên quan với sức mạnh cần thiết, mặc dù:

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

Bằng cách này, mỗi mục đầu vào có thể tạo ra 0 hoặc nhiều mục đầu ra. Bạn có thể sử dụng điều này để xây dựng chức năng bạn muốn:

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]

Hoặc một định nghĩa ngắn gọn hơn về between:

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

4

Với mẫu phù hợp đơn giản, nó sẽ là:

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

Nếu bạn muốn sử dụng mapđể giải quyết điều này, bạn có thể làm một cái gì đó như thế này:

Có một hàm lấy một danh sách phần tử int và trả về 2 với int và zero:

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

Sau đó, bạn có thể gọi bản đồ với chức năng này:

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

Bạn sẽ nhận thấy rằng nó là một danh sách lồng nhau. Đó chỉ là cách maplàm việc. Chúng ta cần một cách để kết hợp danh sách bên trong lại với nhau thành một danh sách. Trường hợp này chúng tôi sử dụngfoldl

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

Vì vậy, cách thức hoạt động của Foldl trong trường hợp này là nó chấp nhận hàm kết hợp, giá trị ban đầu và danh sách để kết hợp.

Vì chúng tôi không cần 0 đầu tiên, chúng tôi có thể bỏ nó:

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

Mã cuối cùng:

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 (++) []là một chút kỳ lạ. Tại sao không chỉ vào concat?
amalloy

1
@amalloy Đúng vậy. Nó chỉ là concatthực hiện chính nó cũng sử dụng một số loại fold. Vì vậy, tôi đoán sử dụng foldlsẽ giúp người khác hiểu nó sâu hơn một chút.
Rinne Hmm

1
concatđược thực hiện bằng cách sử dụng foldrchứ không phải foldl. Bạn có hiểu tại sao điều này thực sự quan trọng?
dfeuer

Tôi không hoàn toàn hiểu chủ đề của foldbản thân. Có cả một wiki liên quan đến chủ đề này. Hiểu đơn giản của tôi foldrlà tốt hơn nhiều cho danh sách vô hạn lười biếng, và foldlhoặc foldl'(phiên bản nghiêm ngặt) tốt hơn cho trường hợp sử dụng chung.
Rinne Hmm

2

Chúng tôi ở đây có thể sử dụng một foldrmẫu trong đó đối với mỗi thành phần trong danh sách ban đầu, chúng tôi sẽ thêm vào đó một mẫu 0:

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

2

Nếu bạn không muốn sử dụng intersperse, bạn có thể tự viết.

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

Nếu bạn thích, bạn có thể sử dụng các Applicativethao tác:

import Control.Applicative

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

Đây là cơ bản định nghĩa được sử dụng trong Data.Sequence.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.