あったらよいのにと思ったメソッド

まとめたものダウンロード

Enumerable

collect_with_index

添字付きcollect。collect と each_index を組み合わせたもの。

ソース

module Enumerable
  def collect_with_index
    r = []
    each_index do |i|
      r << yield(i, self[i])
    end
    r
  end
end

collect_if

各項目を評価した結果が真のものの評価結果を返す。
perlのmapに近い挙動のメソッド
名称を変えました。

ソース

module Enumerable
  def collect_if
    collect do |x|
      yield x
    end.select do |x|
      x
    end
  end
  alias :selective_collect :collect_if
end


Array

listup

上のEnumerable#collect_with_indexをそのまま使ったもの。
書式をパラメータとして与えることが可能。

ソース

class Array
  def listup(fmt = "%d %s\n")
    collect_with_index do |i, v|
      printf fmt, i, v
    end
  end
end

each_n

n個づつのeach

ソース

class Array
  def each_n(n)
    tmp = []
    each_index do |i|
      tmp << self[i]
      if i % n == n - 1
        yield *tmp
        tmp = []
      end
    end
    yield *tmp if tmp.size > 0
  end
end

car, cdr, cadr, cdar, ...

lispのcar, cdr, cadr ...

ソース

class Array
  def method_missing(msgid, *arg)
    if /^c([ad]+)r$/ === msgid.to_s
      r = dup
      $1.scan(/[ad]/).reverse.each do |ad|
        r = if ad == 'a' then r[0] else r[1..-1] end
      end
      r
    else
      super msgid, arg
    end
  end
end

to_h

ArrayからHashを作る

ソース

class Array
  def to_h
    Hash[*self]
  end
end

proc_by

n個毎に処理を行う

ソース

class Array
  def proc_by(n, offset = 0)
    @result = self[0, offset]
    ((length + n - 1 - offset) / n).times do |i|
      @result += self[i * n + offset, n - 1]
      @result += yield(self[i * n + n - 1 + offset]).to_a
    end
    @result
  end
end

divide_by

n個毎に分割する
nがArrayの場合、その数に従って分割。(入れ子のArrayはflattenされる)

ソース

class Array
  def rotate_left
    s = shift
    push s
    s
  end

  def rotate_right
    s = pop
    unshift s
    s
  end

  def divide_by(*order)
    @result = []
    n = order.dup.flatten
    n = n[0] if n.is_a?(Array) && n.length == 1
    if n.is_a? Array
      ptr = 0
      while ptr < length
        s = n.rotate_left
        @result += [self[ptr, s]]
        ptr += s
      end
    else
      ((length + n - 1) / n).times do |i|
        @result += [self[i * n, n]]
      end
    end
    @result
  end
end

grouping

各項がそれぞれArrayであるとして、共通部分を持つ項同士での和集合を作る。
例) [[1, 2], [2, 3], [4, 5]] -> [[1, 2, 3], [4, 5]]

ソース

class Array
  def grouping
    r = []
    each do |x|
      found = false
      r.each do |y|
        if (x & y).size > 0
          y.replace(y | x)
          found = true
          break
        end
      end
      r += [x] unless found
    end
    r
  end
end

cap

配列の配列のすべての項の積集合を求める。
例) [[1, 2], [2, 3]] -> [2]

ソース

class Array
  def cap
    r = self[0]
    each do |x|
      r &= x
    end
    r
  end
end

cup

配列の配列のすべての項の和集合を求める。
例) [[1, 2], [2, 3]] -> [1, 2, 3]

ソース

class Array
  def cup
    r = self[0]
    each do |x|
      r |= x
    end
    r
  end
end

assoc_all

配列の配列のを検索し、第1要素がkeyと等しいすべての配列を配列で返す。
例) [[1, 2], [1, 3], [2, 3]] -> [[1, 2], [1, 3]]

ソース

class Array
  def assoc_all(key)
    r = []
    each do |x|
      r << x if x[0] == key
    end
    r
  end
end

rassoc_all

配列の配列のを検索し、第2要素がvalueと等しいすべての配列を配列で返す。
例) [[1, 2], [1, 3], [2, 3]] -> [[1, 3], [2, 3]]

ソース

class Array
  def rassoc_all(value)
    r = []
    each do |x|
      r << x if x[1] == value
    end
    r
  end
end

each_x

複数の配列から順に値を取り出す。各配列の要素数が異なる場合、最後の値を使う。先頭から繰り返すのいずれかが選択可能。
Arrayの添字が範囲外だった場合にnilを返さないクラス2つも以下に含みます。(LastArray:最後の値を使う, RepeatArray:先頭から繰り返す)
破壊的なメソッドを使うことが可能ですが要素数が同じでない場合、再度破壊的メソッドが使われますので注意が必要です。
例)

  a = RepeatArray.new([1, 2, 3])
  10.times do |n| p [n, a[n]] end
[0, 1]
[1, 2]
[2, 3]
[3, 1]
[4, 2]
[5, 3]
[6, 1]
[7, 2]
[8, 3]
[9, 1]

  a = LastArray.new([1, 2, 3])
  10.times do |n| p [n, a[n]] end
[0, 1]
[1, 2]
[2, 3]
[3, 3]
[4, 3]
[5, 3]
[6, 3]
[7, 3]
[8, 3]
[9, 3]

  ary = [[1, 2, 3, 4, 5], ['A', 'B', 'C'], [1.2, Dir]]
  ary.each_x(:FILL_LAST) do |a, b, c| p [a, b, c] end
[1, "A", 1.2]
[2, "B", Dir]
[3, "C", Dir]
[4, "C", Dir]
[5, "C", Dir]
  ary.each_x(:FILL_REPEAT) do |a, b, c| p [a, b, c] end
[1, "A", 1.2]
[2, "B", Dir]
[3, "C", 1.2]
[4, "A", Dir]
[5, "B", 1.2]

ソース

require 'delegate'

class RepeatArray<DelegateClass(Array)
  def initialize(value)
    super
  end

  alias get_a []
  def [](idx)
    get_a(idx % size)
  end

  alias set_a []=
  def []=(idx, value)
    set_a(idx % @value.size, value)
  end
end

class LastArray<DelegateClass(Array)
  def initialize(value)
    super
  end

  alias get_a []
  def [](idx)
    if idx >= size
      get_a(size - 1)
    else
      get_a(idx)
    end
	end

  alias set_a []=
  def []=(idx, value)
    if idx >= size
      set_a(size - 1, value)
    else
      set_a(idx, value)
    end
  end
end

class Array
  FILL_REPEAT = :FILL_REPEAT
  FILL_LAST   = :FILL_LAST

  def each_x(opt = :FILL_LAST)
    min = max = self[0].size
    accessor = collect do |i|
      min = i.size if i.size < min
      max = i.size if i.size > max
      if opt == :FILL_LAST
        SimpleDelegater.new(LastArray.new(i))
      else
        SimpleDelegater.new(RepeatArray.new(i))
      end
    end
    (0...max).each do |i|
      tmp = accessor.collect do |x| x[i] end
      yield tmp
    end
  end
end


back