tags:

views:

55

answers:

4

I'm trying to write a function that would apply the function to just one item if it's not a collection, or else apply that function to each of the collections elements. For example:

replace spaces with underscores

foo 'a bear' => 'a_bear'
foo ['a bear', 'a bee'] => ['a_bear', 'a_bee']

Is this possible?

+1  A: 

It depends on how you define "collection". The most natural option would probably be either "any Enumerable" or even "anything with an each method". However this leads to a problem because Strings are Enumerable, too - in ruby 1.8, at least.

If you only need it to work with arrays, it's easy:

def foo(x)
  if x.is_a? Array
    x.map {|item| foo(item)}
  else
    # Do something with x
  end
end
sepp2k
A: 
def foo x
    f = ->(x){x.tr ' ','_'}
    x.is_a?(Enumerable) ? x.map{|i|f[i]} : f[x]
end

Hm... I like sepp2k's recursive solution.

def foo x
    x.is_a?(Enumerable) ? x.map{|i|foo i} : x.tr(' ','_')
end
Nakilon
A: 

Not sure if I'm misreading the question or not. The below will make it so a function will treat either a single element or an array of elements the same way. Just array-ifies the argument if it's not already an array, and undoes that at the end if necessary.

def foo(x)
  x = [x] unless x.is_a? Array
  # do array stuff to x
  return result.size > 1 ? result : result.first
end
tfe
Not very exact; what happens if x == [] or x == [1]?
steenslag
A: 

You may be interested in the splat operator

def foo(x)
  [*x].map {|item| item.gsub(" ", "_")}
end

Unfortunately, this'd return foo("a bear") as ["a_bear"], rather than "a_bear" without the array.

Andrew Grimm
And one more way with the same result: `[x].flatten.map{`
Nakilon