LoginSignup
6
1

【Ruby】Array#cycle_each_cons が欲しい

Last updated at Posted at 2023-05-06

たとえば

ary = [:a, :b, :c]

が与えられたときに

[
  [:a, :b],
  [:b, :c],
  [:c, :a]
]

とか

[
  [:a, :b, :c],
  [:b, :c, :a],
  [:c, :a, :b]
]

とかについてループを回したい,ということがよくある。

要するに,与えられた配列のお尻と頭が繋がった円環状の構造についての each_cons だ。
each_cons の cyclic 版とでも言おうか。

これは,以下のように書ける。組み込みクラスの Array を拡張しちゃうので,refinement を使ってお行儀よくいこう。

module CycleEachConsToArray
  refine Array do
    def cycle_each_cons(n)
      return Enumerator.new{ cycle_each_cons(n, &_1) } unless block_given?

      cycle.each_cons(n).take(length).each{ yield _1 }
    end
  end
end

これを使うときは,使いたい場所で

using CycleEachConsToArray

してから

p %w[A B C].cycle_each_cons(2).to_a
# => [["A", "B"], ["B", "C"], ["C", "A"]]

%w[A B C D].cycle_each_cons(3) do |ary|
  puts ary.join("-")
end
# => A-B-C
#    B-C-D
#    C-D-A
#    D-A-B

のようにする。

Array に限定せず Enumerable でやれば応用が広がるように思うかもしれないが,長さがあらかじめ分かる必要があるので,一般の Enumerable についてはできない。
有限の長さを持つ「Array でない Enumerable オブジェクト」に使いたいときは to_a してから使えばいい。

6
1
9

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1