2017-09-08 9 views
0

私は日付の差が> 10日であるスプリットを導入することにより、次の配列を分割したいですグループにシーケンシャル日付の配列:スプリット10日以上離れて

dates = [Date.parse('2017-06-26'), Date.parse('2017-07-04'), Date.parse('2017-11-30')] 
#=> [Mon, 26 Jun 2017, Tue, 04 Jul 2017, Thu, 30 Nov 2017] 

なるはずです次のようになります。

[[Mon, 26 Jun 2017, Tue, 04 Jul 2017], [Thu, 30 Nov 2017]] 

これまでは非常に手続き的な方法がありました。これは、分割する配列、異なるグループのメンバ間の最小の差、および差を得るために評価する属性をパラメータとして受け取ります。この方法についての私のように物事が1ということです

def split_by_attribute_diff array, split_size, attribute = :itself  
    groups = [] 
    current_group = [] 
    previous = current = nil 
    array.sort_by(&attribute).each do |e| 
    previous = current 
    current = e 
    if previous && current.send(attribute) - previous.send(attribute) > split_size 
     if current_group.count > 0 
     groups << current_group 
     current_group = [] 
     end 
    end 
    current_group << current 
    end 
    if current_group.count > 0 
    groups << current_group 
    end 

    groups 
end 
を(差分を決定するために使用される値がちょうど日付そのものなようにDateオブジェクトの私のアレイの場合、私は、最後のパラメータをオフのままにします) )それは動作します、2)アルゴリズムの複雑さはsort_byのものです - 配列がソートされた後、それはたった1回トラバースされます。 私が気に入らない唯一のことは、もっとシンプルになっているように見えるということです。私がここでやっていることを達成するためのRuby-ishの方法がありますか?あなたが適切にRubyで、論理テストに基づいて小さなチャンクに配列を切り分けるために、具体的な特定の chunk_whileEnumerableライブラリを活用する場合

+0

https://stackoverflow.com/questions/21024521/grouping-an-array-by-comparing-2-adjacent-elements – AbM

答えて

3

それはハードである必要はありません。

require 'date' 

dates = %w[ 
    2017-06-26 
    2017-07-04 
    2017-11-21 
    2017-11-30 
    2017-12-30 
].map { |d| Date.parse(d) } 

r = dates.chunk_while do |a,b| 
    a + 10 > b 
end 

r.to_a.map { |a| a.map { |d| d.strftime('%Y-%m-%d') } } 
# => [["2017-06-26", "2017-07-04"], ["2017-11-21", "2017-11-30"], ["2017-12-30"]] 
+1

...または 'R = dates.slice_when行う|、B | 「a + 10エンド」となる。 –

+0

[配列#マップ](http://ruby-doc.org/core-2.4.0/Array.html#method-i-map)が[Enumerable#map]より優先されない限り、to_aは必要ありません(http ://ruby-doc.org/core-2.4.0/Enumerable.html#method-i-map)。 –

+0

私は 'slice_when {| a、b | b-a> 10} 'となりますが、それらはすべて同等です。 – Stefan

1

マイこれと同様の問題に対して、Enumerable#chunk_while(v2.3で新機能)またはEnumerable#slice_when(v2.2で新機能)を使用することをお勧めします。ただし、2.2より前のバージョンのRubyをサポートする必要がある場合は、次のような方法を使用できます。

require 'date' 

def group_em(dates) 
    fmt = '%Y-%m-%d' 
    dates.each_with_object([[]]) do |d,a| 
    if a.last.empty? || Date.strptime(d,fmt) <= Date.strptime(a.last.last,fmt) + 10 
     a.last << d 
    else 
     a << [d] 
    end 
    end 
end 

group_em %w| 2017-06-26 2017-07-04 2017-11-21 2017-11-30 2017-12-30 | 
    #=> [["2017-06-26", "2017-07-04"], ["2017-11-21", "2017-11-30"], ["2017-12-30"]] 
+0

あなたはどういう意味ですか?「chunk_while」または「slice_when」が使用できないときはいつでも_ _ですか? – Stefan

+0

@Stefan、私は明確にするために編集しました(そして、方法を少し簡略化するために)。ありがとう。 –

関連する問題