n個の要素のグループを作成するライブラリ内のリストに対する操作はありますか?例:n = 3
groupInto 3 [1,2,3,4,5,6,7,8,9] = [[1,2,3],[4,5,6],[7,8,9]]
そうでない場合、どうすればよいですか?
Hoogleをすばやく検索すると、そのような機能はないことがわかりました。一方、split
パッケージには、と呼ばれるものがあるとの回答がありましたchunksOf
。
ただし、自分で行うことはできます
group :: Int -> [a] -> [[a]]
group _ [] = []
group n l
| n > 0 = (take n l) : (group n (drop n l))
| otherwise = error "Negative or zero n"
もちろん、いくつかの括弧は削除できます。コードの機能を理解するために、ここに残しました。
基本的なケースは単純です。リストが空の場合は常に、空のリストを返すだけです。
n
が正の場合、再帰的なケースが最初にテストされます。n
is以下の場合0
、無限ループに入りますが、それは望ましくありません。take
次に、and drop
:を使用してリストを2つの部分に分割しtake
、最初のn
要素をdrop
返し、他の要素を返します。次に、n
元のリストの他の要素に関数を適用して取得したリストに最初の要素を追加します。
この関数は、他の同様の関数の中でも、人気のある分割パッケージに含まれています。
> import Data.List.Split
> chunksOf 3 [1,2,3,4,5,6,7,8,9]
[[1,2,3],[4,5,6],[7,8,9]]
ミハイが指摘したように、自分で書くことができます。ただし、 -の組み合わせsplitAt
のように入力リストに2つのパスを必要としないため、この関数を使用します。take
drop
chunks :: Int -> [a] -> [[a]]
chunks _ [] = []
chunks n xs =
let (ys, zs) = splitAt n xs
in ys : chunks n zs
これは一般的なパターンです。反復を繰り返すことにより、シード値(この場合は入力リスト)からリストを生成します。このパターンはunfoldr
関数に取り込まれます。少し変更したバージョンで使用できます(より簡潔なバージョンを提供してくれたWill NesssplitAt
に感謝します)。
chunks n = takeWhile (not . null) . unfoldr (Just . splitAt n)
つまり、要素unfoldr
のチャンクを生成するn
と同時に、入力リストをn
要素ごとに短縮し、空のリストを取得するまでこれらのチャンクを生成します。この時点で、最初の入力は完全に消費されます。
もちろん、他の人が指摘しているように、モジュールの既存の関数を使用する必要がありsplit
ます。しかし、標準のHaskellライブラリのリスト処理機能に慣れることは常に良いことです。
これはしばしば「チャンク」と呼ばれ、にない最も頻繁に言及されるリスト操作の1つですbase
。パッケージsplit
はそのような操作を提供しますが、ハドックのドキュメントをコピーして貼り付けます。
> chunksOf 3 ['a'..'z']
["abc","def","ghi","jkl","mno","pqr","stu","vwx","yz"]
+PKG_NAME
さらに、私の希望に反して、hoogleはライブラリの小さなセット(GHCまたはおそらくHPで提供されるもの)のみを検索しますが、 -hoogle withを使用して、検索にパッケージを明示的に追加できますInt -> [a] -> [[a]] +split
。このため、ハヨを使う人もいます。