🗓️

数字や日付が連続しているかを判定する方法

2024/02/08に公開

こんにちは!
ラブグラフエンジニアのひろです。

日付を一覧で表示する場所で、通常は 「2024年1月1日、2024年1月3日、2024年1月4日」 と羅列し、連続している日付だったら 「2024年1月1日~2024年1月3日」 のように省略して表示したいケースが出てきました。
パッと方法がわからなかったので書き残しておきます。

方法

each_cons(2).all? { |a, b| (b - a).to_i == 1 } を使いました。
each_cons(2)で2つずつ値を取り出し、差分が1(つまり並んでいる)かどうかを検証していく方法です。
(順番がバラバラの配列では機能しないので、事前に sort して昇順に並び替える必要があります)

日付が連続しているかどうかの例

日付が連続しているかどうか.rb
# Range クラスにも使える
dates = (Date.new(2024,1,1)..Date.new(2024,1,3))
dates.each_cons(2).all? { |a, b| (b - a).to_i == 1 }
=> true # 連続している

dates = [Date.new(2024,1,1), Date.new(2024,1,3), Date.new(2024,1,4)]
dates.each_cons(2).all? { |a, b| (b - a).to_i == 1 }
=> false # 連続していない

# 月を跨いでも大丈夫
dates = [Date.new(2023,12,31), Date.new(2024,1,1), Date.new(2024,1,2)]
dates.each_cons(2).all? { |a, b| (b - a).to_i == 1 }
=> true

数字が連続しているかどうかの例

数字が連続しているかどうか.rb
numbers =  [1,2,3,4,5,8,7,9,6]
numbers.each_cons(2).all? { |a, b| (b - a).to_i == 1 }
=> false # そのままだと連続していない
numbers.sort.each_cons(2).all? { |a, b| (b - a).to_i == 1 }
=> true # 並び替えると連続している

numbers = [1,2,4,5,6]
numbers.each_cons(2).all? { |a, b| (b - a).to_i == 1 }
=> false # 連続していない

終わりに

以上、バブルソートのようなイメージで比較して、配列の中身が連続しているかどうか判断する方法でした。
each_cons メソッドは知ってはいたものの、あまり使い所がなかったので、今回活かせる形が見つかってよかったです。

ラブグラフのエンジニアブログ

Discussion