Home > Mobile >  Idiomatic way to receive an object or array of objects, transform them, and add to existing array
Idiomatic way to receive an object or array of objects, transform them, and add to existing array

Time:07-23

I have a method that can receive either a single object, or an array of those objects. (The YAML file I'm pulling from sometimes has foo: bar and sometimes a list of foo: [bar1, bar2].)

Each time this method is called, it should transform the value or values, and add them to an internal array.

I originally had this:

class YamlEater
  def initialize
    @foos = []
  end

  def add(o)
    if o.is_a?(Array)
      o.each{ self.add(_1) }
    else
      @foos << FooItem.new(o)
    end
  end
end

After I needed to use that pattern in many different methods, I changed it to a non-recursive, more terse version that's splat-heavy and perhaps only a golfer could love:

  def add(o)
    @foos.push(*[*o].map{ FooItem.new(_1) })
  end

I'm thinking there's a more elegant way to accomplish the same goal, and hoping someone will share it.

CodePudding user response:

I'd probably use Kernel#Array and Array#concat:

def add(o)
  @foos.concat(Array(o).map { FooItem.new(_1) })
end

That nicely handles o.nil? as a bonus.

CodePudding user response:

As I'm sure you know, you could eliminate one splat by using Array#concat:

[1,2].concat([*[4,5]].map { |e| 2*e })
  #=> [1, 2, 8, 10]
[1,2].concat([*4].map { |e| 2*e })
  #=> [1, 2, 8]

or Array# :

[1,2]   [*[4,5]].map { |e| 2*e }
  #=> [1, 2, 8, 10]
[1,2]   [*4].map { |e| 2*e }
  #=> [1, 2, 8]
  • Related