【问题标题】:How to define a Ruby method that either takes an Array or a String?如何定义一个接受数组或字符串的 Ruby 方法?
【发布时间】:2015-07-29 15:00:25
【问题描述】:

我定义了一个采用(字符串)数组的方法,比如

def list(projects)
  puts projects.join(', ')
end

list(['a', 'b'])

但是,作为使用仅由单个 String 元素组成的 Array 调用它的简写,我希望相同的函数也接受单个普通字符串,例如

  list('a')

在方法中处理这个问题的 Ruby 方法是什么?

【问题讨论】:

  • Array(projects).join(', ')
  • 把评论变成答案,这是正确的方法。
  • 说真的,@LeeJarvis,将其发布为答案,以便我们对其进行投票。
  • @DavidMoles:18 个月后,我认为李不会介意其他人接受他的评论并将其作为答案发布。坦率地说,使用别人的评论作为答案的基础并不违反社区标准,即使评论只有几分钟。一个像样的答案比一个随意的评论需要更多的努力,而且评论者通常无意投入这种努力。拥有这个想法并提供有用的东西的人有更多的权力。

标签: arrays ruby string


【解决方案1】:

为什么不这样:

def list(*projects)
  projects.join(', ')
end

然后你可以用尽可能多的参数调用它

list('a')
#=> "a"
list('a','b')
#=> "a, b"
arr = %w(a b c d e f g)
list(*arr)
#=> "a, b, c, d, e, f, g"
list(arr,'h','i')
#=> "a, b, c, d, e, f, g, h, i"

splat (*) 会自动将所有参数转换为数组,这将允许您毫无问题地传递数组和/或字符串。它也适用于其他对象

list(1,2,'three',arr,{"test" => "hash"}) 
#=> "1, 2, three, a, b, c, d, e, f, g, {\"test\"=>\"hash\"}"

感谢@Stefan 和@WandMaker 指出Array#join 可以处理嵌套数组

【讨论】:

  • @SergioTulentsev 我知道我只是想展示它的所有使用方式,而不用担心错误。另外,最初我没有 flatten 在那里,然后我想既然 OP 要求传递一个真正的数组,这将是处理这个问题的最简单方法。
  • 为什么需要flatten?当我尝试projects.join(', ') 时,它似乎给出了预期的结果
  • @WandMaker 没有flatten, list(['a', 'b']) 将导致嵌套数组。在这种情况下删除 flatten 有效,因为 join 可以处理嵌套数组。
  • _这将允许您毫无问题地传递一个数组和/或一个字符串_—我认为这不是完全正确的。它之所以有效,是因为 join 处理嵌套数组,但考虑类似 def count_args(*p); p.size; endcount_args(*arr) 将返回 7,但 count_args(arr) 将返回 1。调用者仍然需要知道如何分解数组。
  • @engineersmnky 很抱歉你把它当成了个人。如果您在搜索信息时遇到我的一个答案并发现它会将您引向错误的方向,请务必发表评论并投反对票。
【解决方案2】:

可以查看输入的类型,例如:

>> a = ['foo', 'bar']
=> ['foo', 'bar']
>> a.is_a? Array
=> true

你也可以用is_a?检查字符串

你最终会得到一些链接:

def list(projects)
    if projects.is_a? Array
        puts projects.join(', ')
    else
        puts projects
    end
end

list('a') # a
list(['a', 'b']) # a, b

在 Ruby 中有很多方法可以做到这一点,respond_to?kind_of? 也可以使用

【讨论】:

    【解决方案3】:

    一种方法是您可以对输入进行类型检查:

    def list(projects)
      if projects.is_a?(String)
        projects = [projects]
      end
      puts projects.join(', ')
    end
    

    或者您可以使用Array() 将字符串自动转换为数组,或者保留现有数组:

    def list(projects)
      Array(projects).join(', ')
    end
    

    【讨论】:

      【解决方案4】:
      def list(projects)
        puts Array(projects).join(', ')
      end
      
      list ['a', 'b']
      a, b
      list 'a'
      a
      

      也可以写成

      puts [*projects].join(', ')
      

      警告:不要使用这个。

      我发布此解决方案只是为了展示它可以完成的两种方法。 @sawa 在他现在已删除的答案中是正确的:不应允许该方法的用户将数组作为参数传递。相反,它们应该仅限于传递单个元素。如果:

      arr = [1,2,3]
      

      该方法将由以下之一调用:

      list 1
      list 1,2
      list 1,2,3
      list *arr
      

      但不是:

      list arr
      

      这简化了方法并使其应用更加一致。问问自己:为什么允许arr 代替*arr?保存一个字符?

      执行此操作的方法是 @engineersmnky 的答案,删除了 .flatten

      【讨论】:

      • 我已投票取消删除sawa's answer,接受要么 数组 对象列表是要走的路。试图同时处理这两个问题很麻烦。
      • @Stefan,我不知道有人可以投票取消删除答案。这很奇怪,但现在有两票。也许sawa会屈服于我们的意愿并自愿取消删除它。
      • 为了记录,我不建议删除flatten :)
      • @Sergio,我不知道我是怎么完全误读你的评论的,但是由于一个字符串没有响应flatten,我不明白你的意思。
      • 这是关于我任何一个答案的最长对话,甚至不在我的答案中。 :)
      【解决方案5】:

      如果它响应join,我会询问提供的值:

      def list(projects)
        projects.respond_to?(:join) ? projects.join(', ') : projects 
      end
      

      【讨论】:

        猜你喜欢
        • 2020-06-30
        • 1970-01-01
        • 2019-08-30
        • 1970-01-01
        • 2014-04-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-07-08
        相关资源
        最近更新 更多