在一個日期數組中列出丟失的月份

[英]Listing missing months in an array of dates


I have a list of transactions in an array.

我有一個數組中的事務列表。

=> [Wed, 23 Oct 2013, Mon, 18 Nov 2013, Fri, 22 Nov 2013, Mon, 13 Jan 2014, Tue, 28 Jan 2014, Mon, 03 Feb 2014, Mon, 10 Feb 2014, Tue, 18 Feb 2014, Fri, 07 Mar 2014, Mon, 31 Mar 2014, Mon, 07 Apr 2014, Tue, 10 Jun 2014, Mon, 30 Jun 2014, Mon, 22 Sep 2014, Mon, 06 Oct 2014, Fri, 14 Nov 2014, Tue, 18 Nov 2014, Fri, 26 Dec 2014, Thu, 15 Jan 2015, Mon, 23 Mar 2015, Mon, 20 Apr 2015]

I need to compare the dates of each transaction and list any months that are missing in the list of months and year. Here is what I have now...

我需要比較每筆交易的日期,並列出在月份和年度列表中缺失的月份。這是我現在擁有的……

@find_transactions = (@user.transactions.find_all { |t| (t.name 'name' })
@trans_dates = @find_transactions.map(&:date).sort!.map { |s| Date.strptime(s, '%Y-%m') }.each_cons(2).map{ |d1,d2| d1.next_month == d2 }

This method currently gives me a true or false if each month is there but I need to actually have the method print a list of months that are missing. I would like to have it print the month and year together.

如果每個月都有,這個方法現在會給我一個真或假的值,但是我需要讓這個方法打印一個丟失的月的列表。我想把月和年一起印出來。

Here is the response this method gives me...

這是這個方法給我的反應……

=> [true, false, true, false, false, true, false, true, false, false, false, true, true]

I want a response like this...

我想要這樣的回答……

=> [March 2015, December 2014, September 2014]

Thanks in advance!

提前謝謝!

3 个解决方案

#1


3  

Edit: For array already being composed of date objects you can do:

編輯:對於已經由日期對象組成的數組,您可以這樣做:

require 'date'

dates = [Wed, 23 Oct 2013, Mon, 18 Nov 2013, Fri, 22 Nov 2013, Mon, 13 Jan 2014, Tue, 28 Jan 2014, Mon, 03 Feb 2014, Mon, 10 Feb 2014, Tue, 18 Feb 2014, Fri, 07 Mar 2014, Mon, 31 Mar 2014, Mon, 07 Apr 2014, Tue, 10 Jun 2014, Mon, 30 Jun 2014, Mon, 22 Sep 2014, Mon, 06 Oct 2014, Fri, 14 Nov 2014, Tue, 18 Nov 2014, Fri, 26 Dec 2014, Thu, 15 Jan 2015, Mon, 23 Mar 2015, Mon, 20 Apr 2015]

all_dates = []
dates.first.upto(dates.last) {|x| all_dates << x.strftime('%b %Y') if x.day == 1 || x == dates.first}

d = dates.map {|x| x.strftime('%b %Y')}.uniq

p (all_dates - d)
  #=> ["Dec 2013", "May 2014", "Jul 2014", "Aug 2014", "Feb 2015"]

Edit: Below methods are for an array of date strings

編輯:下面的方法是用於數組的日期字符串。

You can try this:

你可以試試這個:

require 'date'

dates = ["Wed, 23 Oct 2013", "Mon, 18 Nov 2013", "Fri, 22 Nov 2013", "Mon, 13 Jan 2014", "Tue, 28 Jan 2014", "Mon, 03 Feb 2014", "Mon, 10 Feb 2014", "Tue, 18 Feb 2014", "Fri, 07 Mar 2014", "Mon, 31 Mar 2014", "Mon, 07 Apr 2014", "Tue, 10 Jun 2014", "Mon, 30 Jun 2014", "Mon, 22 Sep 2014", "Mon, 06 Oct 2014", "Fri, 14 Nov 2014", "Tue, 18 Nov 2014", "Fri, 26 Dec 2014", "Thu, 15 Jan 2015", "Mon, 23 Mar 2015", "Mon, 20 Apr 2015"]

all_dates = []
d = dates.map {|x| Date.parse(x[8..-1])}.uniq
counter = d.first

until counter == d.last
  all_dates << counter
  counter = counter.next_month
end


p (all_dates - d).map {|x| x.strftime('%b %Y')}
  #=> ["Dec 2013", "May 2014", "Jul 2014", "Aug 2014", "Feb 2015"]

Another (more concise) way would be:

另一種(更簡明)的方法是:

require 'date'

dates = ["Wed, 23 Oct 2013", "Mon, 18 Nov 2013", "Fri, 22 Nov 2013", "Mon, 13 Jan 2014", "Tue, 28 Jan 2014", "Mon, 03 Feb 2014", "Mon, 10 Feb 2014", "Tue, 18 Feb 2014", "Fri, 07 Mar 2014", "Mon, 31 Mar 2014", "Mon, 07 Apr 2014", "Tue, 10 Jun 2014", "Mon, 30 Jun 2014", "Mon, 22 Sep 2014", "Mon, 06 Oct 2014", "Fri, 14 Nov 2014", "Tue, 18 Nov 2014", "Fri, 26 Dec 2014", "Thu, 15 Jan 2015", "Mon, 23 Mar 2015", "Mon, 20 Apr 2015"]

all_dates = []
d = dates.map {|x| Date.parse(x[8..-1])}.uniq

d.first.upto(d.last) {|x| all_dates << x if x.day == 1}

p (all_dates - d).map {|x| x.strftime('%b %Y')}
  #=> ["Dec 2013", "May 2014", "Jul 2014", "Aug 2014", "Feb 2015"]

#2


2  

This is one way you could do that.

這是一種方法。

Code

代碼

require 'date'

def missing_months(dates)    
  a = dates.map { |s| d = Date.strptime(s, '%a, %d %b %Y'); d - d.day + 1 }
  (all_months_in_range(*a.minmax) -a).map { |d| d.strftime('%b %Y') } 
end

def all_months_in_range(f,l)
  (12*(l.year-f.year)+l.month-f.month+1).times.map do |i|
    y,m = (f.month+i).divmod(12)
    y += f.year
    (m=12; y-=1) if m ==0
    Date.new(y,m)
  end
end

Example

例子

dates = ['Wed, 23 Oct 2013', 'Mon, 18 Nov 2013', 'Fri, 22 Nov 2013',
         'Fri, 14 Nov 2014', 'Tue, 18 Nov 2014', 'Fri, 26 Dec 2014',
         'Mon, 13 Jan 2014', 'Tue, 28 Jan 2014', 'Mon, 03 Feb 2014',
         'Mon, 31 Mar 2014', 'Mon, 07 Apr 2014', 'Tue, 10 Jun 2014',
         'Mon, 30 Jun 2014', 'Mon, 22 Sep 2014', 'Mon, 06 Oct 2014',
         'Mon, 10 Feb 2014', 'Tue, 18 Feb 2014', 'Fri, 07 Mar 2014',
         'Thu, 15 Jan 2015', 'Mon, 23 Mar 2015', 'Mon, 20 Apr 2015']

missing_months(dates)     
  #=> ["Dec 2013", "May 2014", "Jul 2014", "Aug 2014", "Feb 2015"] 

Notice that the dates needn't be sorted.

注意,日期不需要排序。

Explanation

解釋

For the example above:

上面的例子:

  a = dates.map { |s| d = Date.strptime(s, '%a, %d %b %Y'); d - d.day + 1 }
    #=> [#<Date: 2013-10-01 ((2456567j,0s,0n),+0s,2299161j)>,
    #    #<Date: 2013-11-01 ((2456598j,0s,0n),+0s,2299161j)>,
    #   ...
    #    #<Date: 2015-04-01 ((2457114j,0s,0n),+0s,2299161j)>] 

Notice that each of these dates is on the first of the month. Next, obtain the first and last of these dates:

請注意,這些日期都在每個月的第一天。接下來,獲取第一個和最后一個日期:

  f,l = a.minmax
  f #=> [#<Date: 2013-10-01 ((2456567j,0s,0n),+0s,2299161j)>,
  l #=>  #<Date: 2015-04-01 ((2457114j,0s,0n),+0s,2299161j)>]

Now pass f and l to all_months_in_range to create an array that contains a date object for the first day of each month between f and l.

現在,將f和l傳遞給all_months_in_range,以創建一個數組,該數組包含f和l之間每個月的第一天的日期對象。

  b = all_months_in_range(f,l) 
    #=> [#<Date: 2013-10-01 ((2456567j,0s,0n),+0s,2299161j)>,
    #    #<Date: 2013-11-01 ((2456598j,0s,0n),+0s,2299161j)>,
    #    ...
    #    #<Date: 2015-04-01 ((2457114j,0s,0n),+0s,2299161j)>] 

  b.size #=> 19 

I will skip an explanation of this helper method, as it is quite straightforward.

我將跳過對這個helper方法的解釋,因為它非常簡單。

Compute that difference between arrays b and a to obtain the missing beginning-of-month dates:

計算數組b和數組a之間的差異,以獲得缺失的月初日期:

  c = b-a
    #=> [#<Date: 2013-12-01 ((2456628j,0s,0n),+0s,2299161j)>,
    #    #<Date: 2014-05-01 ((2456779j,0s,0n),+0s,2299161j)>,
    #    #<Date: 2014-07-01 ((2456840j,0s,0n),+0s,2299161j)>,
    #    #<Date: 2014-08-01 ((2456871j,0s,0n),+0s,2299161j)>,
    #    #<Date: 2015-02-01 ((2457055j,0s,0n),+0s,2299161j)>] 

Lastly, convert these dates to the desired format:

最后,將這些日期轉換為所需的格式:

 c.map { |d| d.strftime('%b %Y') } 
   #=> ["Dec 2013", "May 2014", "Jul 2014", "Aug 2014", "Feb 2015"]

Addendum: after reading @Sid's answer, I see I could have saved myself some trouble in my helper method by using Date#next_month:

附錄:在閱讀了@Sid的答案后,我發現我可以使用日期#next_month為我的助手方法省去一些麻煩:

def all_months_in_range(f,l)
  (12*(l.year-f.year)+l.month-f.month+1).times.map { |i| f.next_month(i) }
end

#3


1  

This isn't very elegant, but it worked. I started with your original code, @SupremeA, and built off of that.

這不是很優雅,但它起作用了。我從你的原始代碼@SupremeA開始,並以此為基礎。

require 'date'

dates = ['Wed, 23 Oct 2013', 'Mon, 18 Nov 2013', 'Fri, 22 Nov 2013', 'Mon, 13 Jan 2014', 'Tue, 28 Jan 2014', 'Mon, 03 Feb 2014', 'Mon, 10 Feb 2014', 'Tue, 18 Feb 2014', 'Fri, 07 Mar 2014', 'Mon, 31 Mar 2014', 'Mon, 07 Apr 2014', 'Tue, 10 Jun 2014', 'Mon, 30 Jun 2014', 'Mon, 22 Sep 2014', 'Mon, 06 Oct 2014', 'Fri, 14 Nov 2014', 'Tue, 18 Nov 2014', 'Fri, 26 Dec 2014', 'Thu, 15 Jan 2015', 'Mon, 23 Mar 2015', 'Mon, 20 Apr 2015']

new_dates = []
dates.each { |d| new_dates.push(Date.parse(d).strftime('%B %Y')) }
sorted_dates = new_dates.map { |s| Date.strptime(s, '%B %Y') }.sort.uniq
missing_months = []
sorted_dates.each_cons(2) do |d1,d2| 
  d = d1
  while d.next_month != d2 
    missing_months.push(d.next_month.strftime('%B %Y')) 
    d = d >> 1
  end 
end
p missing_months

=> ["December 2013", "May 2014", "July 2014", "August 2014", "February 2015"]

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2015/04/22/725143b8c9ec301d2ba5df40b561a692.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com