droptake

このページではコレクションパイプラインパターンの演算について説明します。詳細については以下をお読みください。

スライス

リスト内の与えられた最初の位置と最後の位置の間の部分シーケンスを返します。

リストの一部が必要な場合は、リストのスライスを取得できます。必要なスライスの種類に応じて、言語によってさまざまな演算子が提供されます。

最も一般的な形式では、任意の範囲の要素をスライスできます。

ruby…
[1,2,3,4,5,6].slice(2..4)
# => [3, 4, 5]
clojure…
(subvec [1 2 3 4 5 6] 2 5)
;; => [3 4 5]

これらの 2 つの基本的な例から、いくつかのポイントがわかります。まず、ほとんどの言語は 0 ベースのインデックスを使用しています。これは、プログラマーが「0、1、2…9」と言って自然に 10 まで数えるからです。

Ruby は包括的な範囲を使用してスライスを指定しますが、clojure は 2 つの数字を使用して開始は含みますが終了は除外します。Ruby の範囲表記では、以下を使用して終了を除外できます。

ruby…
[1,2,3,4,5,6].slice(2...5)
# => [3, 4, 5]

私は三点リーダー形式はほとんど使用せず、一部のプログラマーは「...」と「..」の違いが非常に微妙なのでこの形式を使用することを嫌がっています。

Ruby は配列引数を使用してスライスできます。

ruby…
[1,2,3,4,5,6][2..4]
# => [3, 4, 5]

この形式はパイプライン形式ではあまり読みやすいものではない場合があります。

Clojure の subvec 関数は、一般的にはリストではなくベクトルでのみ機能します。ベクトルでは高速(インデックスが付けられているため)ですが、clojure リストの他の形式では高速ではなくなるため、ベクトルでの操作への制限により、操作の使用の汎用性の低下によるパフォーマンスの低下を回避できます。また、Subvec は clojure パイプラインの慣習に適合せず、コレクション引数が最後の引数ではないため ->> では機能しません。

Clojure では、2 番目の引数を省略してリストの先頭から末尾までスライスできます。Ruby では、範囲で負の数字を使用してこれを行います。

ruby…
[1,2,3,4,5,6].slice(2..-1)
# => [3, 4, 5, 6]
clojure…
(subvec [1 2 3 4 5 6] 2)
;; => [3 4 5 6]

Ruby の範囲では、リストの末尾からカウントするために負の引数を使用できます。

ruby…
[1,2,3,4,5,6].slice(-4..-2)
# => [3, 4, 5]

一般的なスライス操作を使用するのではなく、多くの言語では別の take 関数と drop 関数を優先します。Take は最初の要素を返します(ruby の slice(0..2) と同じ)。

ruby…
[1,2,3,4,5,6].take(3)
# => [1, 2, 3]
clojure…
(take 3 [1 2 3 4 5 6])
;; => (1 2 3)

Drop は最初の要素を破棄します(ruby の slice(-3..-1))。

ruby…
[1,2,3,4,5,6].drop(3)
# => [4, 5, 6]
clojure…
(drop 3 [1 2 3 4 5 6])
;; => (4 5 6)

take と drop をパイプライン方式で処理することで、スライスを形成できます。

ruby…
[1,2,3,4,5,6].take(5).drop(2)
# => [3, 4, 5]
clojure…
(drop 2 (take 5 [1 2 3 4 5 6]))
;; => (3 4 5)

これらの数字は、ruby のスライス演算子の排他的範囲に対応していることに注意してください。

take-drop アプローチは、両方の操作がリスト全体を解決せずに実行できるため、遅延リストに適しています。

リストの末尾から処理する必要がある場合、clojure は take-lastdrop-last を提供します。

clojure…
(take-last 2 [1 2 3 4 5 6])
;; => (5 6)
(drop-last 2 [1 2 3 4 5 6])
;; => (1 2 3 4)