开发者

How can you make a ruby function accept either an individual item or collection of items and do the same thing?

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 undersc开发者_JS百科ores

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

Is this possible?


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


Personally I would use variable args:

def foo(*args)
  args.each { |arg| puts arg }
end

foo("bar")                    # bar
foo("bar", "foobar")          # bar \n foobar
foo(*%w(bar foobar))          # bar \n foobar
a = ["bar", "foobar"]
foo(*a)                       # bar \n foobar
foo("baz", *a)                # baz \n bar \n foobar
a = "bar"
foo(*a)                       # bar

If you don't know whether or not your argument is a string or an array then just prepend it with a *.

I find this gives the maximum flexibility when dealing with arrays which might instead be a single value as I can enter them as just arguments if I am initializing the array or safely pass in the variable if I know it will either be an array or a single argument. It will choke on hashes though.


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.


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜