リストの要素間にゼロを追加しますか?


8

私はすべての要素の間に0を含めるようにhaskellのリストを変更しようとしています。最初のリストがある場合は[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 

回答:



8

これをで行うことはできませんmap。の基本的な特性の1つは、map各出力要素が1つの入力に対応し、その逆も同様であるため、出力は常に入力と同じ数の項目を持つことです。

ただし、必要な機能を備えた関連ツールがあります。

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

このようにして、各入力アイテムは0個以上の出力アイテムを生成できます。これを使用して、必要な関数を作成できます。

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

単純なパターンマッチングでは、次のようになります。

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

これmapを解決するために使用したい場合は、次のようなことができます:

intを取得し、intとゼロの2つの要素リストを返す関数があります。

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

次に、この関数でマップを呼び出すことができます:

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

ネストされたリストであることがわかります。それがまさにmap仕事です。内部リストを1つのリストにまとめる方法が必要です。今回使用するケース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
  [] -> []

1
foldl (++) []少し変です。なぜポイントしないのconcatですか?
アマロイ

1
@amalloyはい、そうです。concat実装自体も何らかのタイプのを使用しているだけですfold。だから私が使うfoldlことは他の人がそれをもう少し深く理解する助けになると思います。
Rinne Hmm、

1
concatfoldrではなくを使用して実装されfoldlます。これが実際に重要な理由を理解していますか?
-dfeuer

私はfold自分の主題を完全に理解していません。この主題に関連するウィキ全体があります。私の単純な理解は、それfoldrが遅延無限リストにはるかに適していること、foldlまたはfoldl'(厳密なバージョン)が一般的なユースケースに適していることです。
Rinne Hmm

2

ここfoldrでは、元のリストの要素ごとに、先頭にを付けるパターンを使用できます0

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

2

を使用したくない場合は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です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.