Ruby: Object.to_a replacement

后端 未结 7 1369
后悔当初
后悔当初 2020-12-25 12:03

I need to convert a passed in argument (single object or collection) to an Array. I don\'t know what the argument is. If it is an Array already, I want to leave it, otherwis

相关标签:
7条回答
  • 2020-12-25 12:26

    Wow, someone just necromanced a really old thread. :-O But since I don't see it included yet, I'll add one more way for completeness' sake:

    arg = [*arg]
    

    This will splat the argument if it already is an array (thus removing one level of nesting) or create a one-argument array otherwise:

    arg = [1,2,3]
    [*arg] #=> [1, 2, 3]
    arg = 1
    [*arg] #=> [1]
    
    0 讨论(0)
  • 2020-12-25 12:28

    Use the method Kernel#Array:

    Array([1,2,3]) #=> [1, 2, 3]
    Array(123) #=> [123]
    

    Yes it may look like a class at first but this is actually a method that starts with a capital letter.

    0 讨论(0)
  • 2020-12-25 12:33

    You can take the duck typing aproach if that suits the problem better, make a list of all the methods you need, and check if the object already have them, if not, make it an array:

    [:[], :each, :etc...].all? { |m| obj.respond_to? m } ? obj : [obj]
    

    The advantage is that you give the object a chance to implement it's own semantics for indexed access.

    0 讨论(0)
  • 2020-12-25 12:34

    I do this a lot, and always use:

    arg = [arg] unless arg.is_a?(Array)
    

    Though if you know you're never passing in arrays as individual arguments you can also do:

    arg = [arg].flatten
    
    0 讨论(0)
  • 2020-12-25 12:35

    I'm not sure if this helps, but what I often need is not that the arg be an array, but that the arg responds to each.

    arg = [arg] unless arg.respond_to? :each
    
    0 讨论(0)
  • 2020-12-25 12:36

    It seems only Object.to_a is deprecated, removing a default to_a and forcing each class to define its own (e.g., Hash.to_a).

    self.to_a       #=> -:1: warning: default `to_a' will be obsolete
    "hello".to_a    #=> ["hello"]
    Time.new.to_a   #=> [39, 54, 8, 9, 4, 2003, 3, 99, true, "CDT"]
    
    h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300  }
    h.to_a   #=> [["a", 100], ["c", 300], ["d", 400]]
    

    If your argument is an instance of Object, try:

    Hash.new(obj).to_a
    

    @Daniel [comment to Ollivier]: The point is that I don't know what the argument is. If it is an array already, I want to leave it, otherwise create a one-element array.

    If that's the case, try:

    obj = [obj] if !obj.is_a?(Array)
    
    0 讨论(0)
提交回复
热议问题