【问题标题】:Ruby longest word in arrayRuby数组中最长的单词
【发布时间】:2011-07-09 22:29:25
【问题描述】:

我构建了这个方法来查找数组中最长的单词,但我想知道是否有更好的方法来完成它。我对 Ruby 很陌生,只是将其作为学习inject 方法的练习。

它返回一个数组中最长的单词,或者一个相等的最长单词的数组。

class Array
  def longest_word
    # Convert array elements to strings in the event that they're not.
    test_array = self.collect { |e| e.to_s }
    test_array.inject() do |word, comparison|
      if word.kind_of?(Array) then
        if word[0].length == comparison.length then
          word << comparison
        else
          word[0].length > comparison.length ? word : comparison
        end
      else
        # If words are equal, they are pushed into an array
        if word.length == comparison.length then
          the_words = Array.new
          the_words << word
          the_words << comparison
        else
          word.length > comparison.length ? word : comparison
        end
      end
    end
  end
end

【问题讨论】:

    标签: ruby enumerable inject


    【解决方案1】:

    我愿意

    class Array
      def longest_word
        group_by(&:size).max.last
      end
    end
    

    【讨论】:

    • 如果你确定你只有字符串,你可以写成self.group_by(&amp;length).max.last,否则你需要一个额外的to_s调用,比如self.group_by{|el|el.to_s.size}.max.last。最后,要在只有一个元素时返回单个字符串,可以在返回之前执行longest_word.size &gt; 1 ? longest_word : longest_word.first
    • 不错!我冒昧地使代码更简洁,但如果您不喜欢这种风格,请恢复
    • OP在问题中说他这样做是为了学习inject,目前还不清楚他是在寻找使用inject的更好方法还是只是一个更好的方法时期。你的对第二种解释和@Mladen Jablanović 对第一种解释是一个很好的答案。两者都得到我的 +1。
    • 一开始是我玩弄inject,但是看到没有这种方法有更短的方法来做这件事很有趣。谢谢!
    • @Marc-André Lafortune 这样更易读,谢谢。
    【解决方案2】:

    Ruby 有一个标准方法来返回列表中的元素,其中包含最大值。

    anArray.max{|a, b| a.length <=> b.length}
    

    或者你可以使用 max_by 方法

    anArray.max_by(&:length)
    

    获取最大长度的所有元素

    max_length = anArray.max_by(&:length).length
    all_with_max_length = anArray.find_all{|x| x.length = max_length}
    

    【讨论】:

    • 这很好,但是 OP“只是将其作为学习注入方法的练习。”
    • 这两种方法都只返回一个元素,而不是一些等长字符串的数组。
    【解决方案3】:

    这是使用inject 的一个(不适用于空数组):

    words.inject(['']){|a,w|
      case w.length <=> a.last.length
      when -1
        a
      when 0
        a << w
      when 1
        [w]
      end
    }
    

    可以简写为

    words.inject(['']){|a,w|
      [a + [w], [w], a][w.length <=> a.last.length]
    }
    

    适合那些喜欢打高尔夫球的人。

    【讨论】:

    • 实际上,这应该适用于空数组,这是显式为累加器提供初始值的(一个)点。
    • 在我的版本中,不知何故,我认为通过累加器隐式地线程化单词长度会更干净,但它并没有完全清理它:-) 你的看起来好多了。跨度>
    • 为了处理空数组,必须使用空数组(而不是像我一样包含空字符串的数组)来启动inject,并使内部的分支更加复杂.但是为了学习inject,我觉得这就够了。
    • 啊,是的,它会返回错误的结果。我在考虑更多关于 Haskell 的问题,其中foldl1 会抛出错误,而foldl 不会,或者我的解决方案在inject 的结果上调用first,对于空数组,这将是nil没有明确的初始累加器,因此引发NoMethodError。 (我应该学会不回答这样的问题,或者让 cmets 匆忙离开,穿着夹克,从字面上走出门的一半:-))
    【解决方案4】:

    两个班轮:

    vc = ['asd','s','1234','1235'].sort{|a,b| b.size <=> a.size}
    vc.delete_if{|a| a.size < vc.first.size} 
    
    
    #Output
    ["1235", "1234"]
    

    或者如果你想使用注入,这使用你的想法,但它更短。

    test_array.inject{ |ret,word|
       ret = [ret] unless ret.kind_of?(Array)
    
       ret << word  if word.size == ret.first.size
       ret = [word] if word.size > ret.first.size
       ret
    }
    

    【讨论】:

    • 此方法在直接应用于数组时不是幂等的。可能不是你所期望的。你可以在这里使用clone。但是解决方案还可以,甚至可能不是最慢的(不知道group_by内置方法的实现细节)
    • @Holger: group_by 使用数组查找,所以基本上是O(n),而sort 比较慢。
    • 您可以使用take_while 而不是delete_if,它会在遇到较小的单词时立即停止。
    【解决方案5】:
    module Enumerable
      def longest_word
        (strings = map(&:to_s)).
          zip(strings.map(&:length)).
          inject([[''],0]) {|(wws, ll), (w, l)|
            case  l <=> ll
            when -1 then [wws, ll] 
            when  1 then [[w], l]
            else         [wws + [w], ll]
            end
          }.first
      end
    end
    

    这个方法只依赖于通用的Enumerable 方法,没有什么Array 专门针对它的,因此我们可以将它拉到Enumerable 模块中,在那里它也可用于Sets 或@987654326 @s,不仅仅是Arrays。

    【讨论】:

    • 这只会返回一个元素,而不是大小相等的单词数组。
    • @steenslag:是的,感谢您的关注。方法名称让我有点失望,我本来希望返回多个单词的方法被称为longest_words(复数)。
    【解决方案6】:

    这个解决方案使用注入方法来累积数组中最长的字符串,然后选择长度最大的字符串。

    动物 = [“老鼠”、“猫”、“鸟”、“熊”、“驼鹿”]

    animals.inject(Hash.new{|h,k| h[k] = []}) { |acc, e| acc[e.size]

    这会返回: [“鼠标”,“鼠标”]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-29
      • 2019-04-28
      • 2018-12-13
      • 1970-01-01
      • 2013-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多