Tech Racho エンジニアの「?」を「!」に。
  • 開発

Rubyのビット演算子でarrayを操作する

こんにちは、hachi8833です。今回はRubyの小ネタです。

Qiitaで「RubyでArrayどうしを加算して一意にするのをuniqメソッド使わずにやる」という記事を見かけておっと思ったので、もう少し調べてみました。

[1] pry(main)> [1,2,3,1]|[2,3,88,4,4,6,7,23,41]
#=> [1, 2, 3, 88, 4, 6, 7, 23, 41]

縦棒演算子|を使用することで、確かに2つのarray全体の重複が解消されました。arrayの内容の順序は保存されるので、.sortで改めてソートをかけることもできます。
この縦棒は何だろうと思ったら、基本的にrubyのビット論理和演算子として使われているものでした。

Rubyで使われる記号の意味

論理和演算子または類似のメソッド。二進数で 0011 | 0101 => 0111。

arrayで別のメソッドが用意されているようなので、ソースを開いてみました。

[29] pry(main)> show-source Array#|
From: array.c (C Method):
Owner: Array
Visibility: public
Number of lines: 19

static VALUE
rb_ary_or(VALUE ary1, VALUE ary2)
{
    VALUE hash, ary3;
    long i;

    ary2 = to_ary(ary2);
    hash = ary_make_hash(ary1);

    for (i=0; i<RARRAY_LEN(ary2); i++) {
        VALUE elt = RARRAY_AREF(ary2, i);
        if (!st_update(RHASH_TBL_RAW(hash), (st_data_t)elt, ary_hash_orset, (st_data_t)elt)) {
            RB_OBJ_WRITTEN(hash, Qundef, elt);
        }
    }
    ary3 = rb_hash_values(hash);
    ary_recycle_hash(hash);
    return ary3;
}

ORがあるならANDもあるだろうと思ってやってみると、やはりビット論理和記号&を使用したメソッドがarrayにありました。

[33] pry(main)> [1,2,3,1]&[88,4,6,7,7,23,41]
#=> []
[34] pry(main)> [1,2,3,4]&[88,4,6,7,7,23,41]
#=> [4]

なおXOR記号の^メソッドはarrayにはありませんでした。

[35] pry(main)> [1,2,3,4]^[88,4,6,7,7,23,41]
NoMethodError: undefined method `^' for [1, 2, 3, 4]:Array
from (pry):29:in `__pry__'

当然ながら、arrayでない数字などに対して|&を使用すると本来のビット演算が動き出してしまいます。

[3] pry(main)> 1|2
#=> 3
[4] pry(main)> 2|3
#=> 3
[5] pry(main)> 3|5
#=> 7
[37] pry(main)> 3&2
#=> 2
[38] pry(main)> 3&1
#=> 1
[39] pry(main)> 3&4
#=> 0

両方ともarrayであることが前提です。

[40] pry(main)> 3|[1,2,3]
TypeError: Array can't be coerced into Fixnum
from (pry):33:in `|'
[41] pry(main)> [1,2,3]|3
TypeError: no implicit conversion of Fixnum into Array
from (pry):34:in `|'

CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。