首页 > 解决方案 > 在填补空白的同时合并两个数组

问题描述

我有一个day对象。它有两个属性:where是一天的名称(“Monday”、“Tuesday” ....),而name它是一个整数。magnitudenamemagnitude

我需要构建一个week必须始终返回一个 7 s 的数组day,一个用于一周中的每一天。

但是,有时,我得到的数组不到 7day秒。IE

days = [<Day name: "Monday", magnitude: 4>, 
        <Day name: "Friday", magnitude: 3>, 
        <Day name: "Sunday", magnitude: 8>]

所以,为了建立一周,我想出了以下代码

default = Date::DAYNAMES.rotate(1).map{ |day| Day.new(name: day, magnitude: 0) }

default.map do |day|
 days.detect do |other|
   other.day == day.day
 end || day
end

这行得通,但我觉得它很丑。我宁愿在两个数组之间进行联合。但是,我必须保留day数组中 s 的顺序。Monday必须始终是第一天而Sunday最后一天。

关于如何改进上述代码的任何想法?

标签: ruby

解决方案


Data

class Day
  attr_accessor :name, :magnitude
  def initialize(name, magnitude)
    @name = name
    @magnitude = magnitude
  end
end

days = [["Monday", 4], ["Friday", 3], ["Sunday", 8]].map {|args|
  Day.new(*args) }
  #=> [#<Day:0x00005a1be9157548 @name="Monday", @magnitude=4>,
  #    #<Day:0x00005a1be91574d0 @name="Friday", @magnitude=3>,
  #    #<Day:0x00005a1be91574a8 @name="Sunday", @magnitude=8>]

Code

require 'date'

h = days.each_with_object({}) { |inst,h| h[inst.name] = inst }
  #=> {"Monday"=>#<Day:0x00005a1be9157548 @name="Monday", @magnitude=4>,
  #    "Friday"=>#<Day:0x00005a1be91574d0 @name="Friday", @magnitude=3>,
  #    "Sunday"=>#<Day:0x00005a1be91574a8 @name="Sunday", @magnitude=8>} 

h.default_proc = ->(h,d) { h[d] = Day.new(d,0) }
  #=> #<Proc:0x00005a1be93ce858@(irb):26 (lambda)> 

h.values_at(*Date::DAYNAMES.rotate(1))
  #=> [#<Day:0x00005a1be9157548 @name="Monday", @magnitude=4>,
  #    #<Day:0x00005a1be93d8ec0 @name="Tuesday", @magnitude=0>,
  #    #<Day:0x00005a1be93d8e98 @name="Wednesday", @magnitude=0>,
  #    #<Day:0x00005a1be93d8e70 @name="Thursday", @magnitude=0>,
  #    #<Day:0x00005a1be91574d0 @name="Friday", @magnitude=3>,
  #    #<Day:0x00005a1be93d8e48 @name="Saturday", @magnitude=0>,
  #    #<Day:0x00005a1be91574a8 @name="Sunday", @magnitude=8>] 

Explanation

See Hash#default_proc= and Hash#values_at. If h does not have a key day the default proc causes h to return a new Day object with @name equal to the value of day and @magnitude equal to zero.

The first two expressions could be combined using (for example) Object#tap:

h = days.each_with_object({}) { |inst,h| h[inst.name] = inst }.
         tap { |h| h.default_proc = ->(h,d) { h[d] = Day.new(d,0) }

推荐阅读