配列(リスト)から特定の条件にマッチする要素のみを取り出すには (array_filter / delete_if / filter / grep / keep_if / partition / reject / select)

各プログラミング言語での、配列から述語関数にマッチする要素のみを取り出した配列を作成する方法。または述語関数にマッチする要素のみのリストとマッチしない要素のみのリストの2つに分ける方法。

Scala PHP Python Ruby Perl CoffeeScript

Scala

以下は、フィルター済みのリストを返し、自身は変更しないメソッド。

Signature:

def scala.collection.Seq[A]#filter(p: A => Boolean): Seq[A]

val lst = List(1, 2, 3, 4, 5);

val filtered = lst.filter(_ % 2 == 1);

println(filtered);
// => List(1, 3, 5)

以下は、条件にマッチする要素のみのリストと、マッチしない要素のみのリストの2つを返すメソッド。

Signature:

// scala.collection.Seq[A]
def partition(p: A => Boolean): (Seq[A], Seq[A])

val lst = List(1, 2, 3, 4, 5);

val (matchList, unmatchList) = lst.partition(_ % 2 == 1);

println(matchList);
// => List(1, 3, 5)

println(unmatchList);
// => List(2, 4)

もし、フィルター済みのリストの要素の数を数えたいだけの場合は、countメソッドを使える。

Signature:

// scala.collection.Seq[A]
def count(p: A => Boolean): Int

このメソッドで条件にマッチした要素の数を取得できる。

PHP

array_filter関数でできる。

$arr = array(1, 2, 3, 4, 5);
$filtered = array_filter($arr, function($elem){
  return $elem % 2 == 1;
});
var_export($filtered);
// 出力結果
// array (
//   0 => 1,
//   2 => 3,
//   4 => 5,
// )

キーはそのまま維持されてフィルタリングされるので、上記例のように添字に欠番が生じることもある。

PHPは普通の配列と連想配列が同じものなので、 array_filter関数は連想配列でも使える。

array_map関数と引数の順番が違うので、要注意。

array_filter 関数 | PHP Manual
http://php.net/manual/ja/function.array-filter.php

ただし、array_filter は遅いので、普通に foreach で回しながら新しい配列を作ったほうが速い、という話もある。

PHPで高速オシャレな配列操作を求めて | Qiita
http://qiita.com/Hiraku/items/190443b33ee7a2167ade

Python

filter関数を使う例

lst = [10, 20, 30, 40, 50]

print filter((lambda x: x < 30), lst)
# => [10, 20]

リストの内包表記を使う例

lst = [10, 20, 30, 40, 50]

print [x for x in lst if x < 30]
# => [10, 20]

Ruby / JRuby

Enumerable#select は条件にマッチする要素のみを抽出した配列を返す。

Enumerable#reject は逆に条件にマッチしない要素のみを抽出した配列を返す。

Enumerable#partition は条件にマッチする要素の配列と、マッチしない要素の配列を返す。返り値は配列の配列になる。

いずれも条件はブロックで表現する。

ArrayEnumerableをインクルードしているので、ArrayでもEnumerableのメソッドを使える。

positive = arr.select {|elem| elem > 0}

positive, negative_or_zero = arr.partition {|elem| elem > 0}

Array#delete_ifArray#reject!reject と同じで条件にマッチする要素を配列から削除するが、 reject と違い、配列自身を変更してしまう破壊的なメソッド。

should_be_positive.delete_if {|elem| elem <= 0}

Array#keep_ifArray#select!Array#delete_if とは逆に条件にマッチしない要素を配列から削除する破壊的なメソッド。

Enumerable#select | Ruby 2.1 リファレンスマニュアル
http://docs.ruby-lang.org/ja/2.1.0/method/Enumerable/i/find_all.html

Enumerable#reject | Ruby 2.1 リファレンスマニュアル
http://docs.ruby-lang.org/ja/2.1.0/method/Enumerable/i/reject.html

Enumerable#partition | Ruby 2.1 リファレンスマニュアル
http://docs.ruby-lang.org/ja/2.1.0/method/Enumerable/i/partition.html

Array#delete_if, Array#reject! | Ruby 2.1 リファレンスマニュアル
http://docs.ruby-lang.org/ja/2.1.0/method/Array/i/delete_if.html

Array#keep_if | Ruby 2.1 リファレンスマニュアル
http://docs.ruby-lang.org/ja/2.1.0/method/Array/i/keep_if.html

Array#select! | Ruby 2.1 リファレンスマニュアル
http://docs.ruby-lang.org/ja/2.1.0/method/Array/i/select=21.html

Perl

grep関数を使う。

grepgrepコマンドと似たイメージだが、行番号を返したりすることはできない。代わりに条件として正規表現以外に任意の述語関数を使える。

奇数のみの新しい配列を作る例

my @arr = (1, 2, 3, 4, 5);
my @newArr = grep { $_ % 2 == 1; } @arr;
print "@newArr";
# => 1 3 5

map関数と組み合わせて、以下のような書き方もできる。 Scalaだとかのメソッドチェーンとは見た目が逆で右から左に処理される。

my @arr = 1..10;
my @newArr = map { $_ * 2 } grep { $_ % 2 == 1; } @arr;
print "@newArr";
# => 2 6 10 14 18

CoffeeScript

配列の内包表記

(elem for elem in arr when elemを使った条件式)
このサイトは筆者(hydrocul)の個人メモの集合です。すべてのページは永遠に未完成です。