检查Ruby中的数组数组中是否不存在值

时间:2013-06-07 20:30:16

标签: ruby

我有一些数据,这些数据排列在一个数组数组中,如下所示:

[[date1, value1], [date2, value2], [date3, value3]]
i.e. [["6-01-13", 5], ["6-03-13", 2], ["6-04-13", 11]]

我的问题是我的绘图实用程序没有绘制“6-02-13”的任何数据,而我希望它绘制为0。

我有另一个有效日期的数组,例如["6-01-13", "6-02-13", "6-03-13", ...]

对于我的数据阵列中尚不存在的所有日期,将[date, 0]插入数据数组的最佳方法是什么? 我不关心数组的排序。

我想我会按照以下方式做点什么:

dates_array.each do |date|
  unless data_array.has_date(date)
    data_array.push([date, 0])
  end
end

但我想不出这个has_date(date)方法应该如何工作而不循环遍历所有日期并检查该日期是否在我的数据数组中表示(这将天真地成为循环循环,因此并不理想)

编辑:现有数据(和日期)作为数组从数据库中提取。

7 个答案:

答案 0 :(得分:5)

将数组数组转换为默认值为零的哈希:

def data_to_hash(data)
  Hash.new(0).merge(Hash[data])
end

data = [["6-01-13", 5], ["6-03-13", 2], ["6-04-13", 11]]

hashed_data = data_to_hash(data)
p hashed_data['6-02-13']
p hashed_data['6-01-13']

输出:

0
5

不在数组中的任何日期都将返回0.使用散列作为数据结构在大型数据集上比在数组中迭代寻找日期要快得多。

回复更新

要使无效键“粘贴”到散列,可以使用Hash #new的块变体:

def data_to_hash(data)
  Hash.new { |h,k| h[k] = 0 }.merge(Hash[data])
end

data = [["6-01-13", 5], ["6-03-13", 2], ["6-04-13", 11]]
hashed_data = data_to_hash(data)

p hashed_data
%w{6-03-13 7-8-99}.each do |d|
  p hashed_data[d]
end
p hashed_data

输出:

{"6-01-13"=>5, "6-03-13"=>2, "6-04-13"=>11}
2
0
{"6-01-13"=>5, "6-03-13"=>2, "6-04-13"=>11, "7-8-99"=>0}

在此示例中,原始数据集中不存在7-8-99,但访问该密钥时设置为0。

答案 1 :(得分:1)

dates_array.each do |date|
  data.push [date, 0] unless data.map(&:first).include? date
end 

这很有效。也许有人可以改进它。

答案 2 :(得分:1)

如果您知道日期范围,则可以预先填充包含该范围的所有日期的数组,并为它们提供默认值零。 array = Array.new(31) {['date', 0]}

只提供实际信息而不是日期。

或者这样做:(date..date+31).to_a.map!(&:to_s).zip([0]*32)

如果您向我提供现有日期项目的方式,我想我会做出更适合您的方式。

答案 3 :(得分:1)

不使用循环的替代方法

dates_present = data.map(&:first)
dates_missing = dates_array - dates_present
data += dates_missing.map { |date| [date, 0] }

答案 4 :(得分:0)

您可以使用以下策略:

dates_array = [["6-01-13", 5], ["6-03-13", 2], ["6-04-13", 11]]
dates_array.push(["16-03-13",0]) unless dates_array.find{|i,j| i == "16-03-13"}
dates_array # => [["6-01-13", 5], ["6-03-13", 2], ["6-04-13", 11], ["16-03-13", 0]]

以下是完整的方法:

def date_check(arr,date)
  arr.push(["16-03-13",0]) unless arr.find{|i,j| i == date}
end

dates_array = [["6-01-13", 5], ["6-03-13", 2], ["6-04-13", 11]]
date_check(dates_array,"16-03-13") # => [["6-01-13", 5], ["6-03-13", 2], ["6-04-13", 11], ["16-03-13", 0]]
date_check(dates_array,"6-01-13") # => nil

答案 5 :(得分:0)

确保从数据库或dates_array.sort!{|a,b| Date.parse(a[0]) <=> Date.parse(b[0])}

中分类数据
(Date.parse(dates_array.first[0])..Date.parse(dates_array.last[0])).collect do |date|
  dates_array.find{|i| i[0] == date} || [date, 0]
end 

我不喜欢接受的答案b / c它需要一个现有的数组。

答案 6 :(得分:0)

data = [["6-01-13", 5], ["6-03-13", 2], ["6-04-13", 11]]
valid_dates = ["6-01-13", "6-02-13", "6-03-13"]

data + ( valid_dates - data.map(&:first) ).map { |d| [d, 0] }
#=> [["6-01-13", 5], ["6-03-13", 2], ["6-04-13", 11], ["6-02-13", 0]]

解释

  • data.map(&:first)只返回日期,即["6-01-13", "6-03-13", "6-04-13"]
  • valid_dates - …计算差异,即缺少日期["6-02-13"]
  • .map { |d| [d, 0] }将这些转化为[<date>, 0]
  • data + …连接数据数组和缺少日期对数组