【问题标题】:Remove adjacent identical elements in a Ruby Array?删除 Ruby 数组中相邻的相同元素?
【发布时间】:2010-03-25 14:29:11
【问题描述】:

Ruby 1.8.6

我有一个包含数值的数组。我想减少它,以便将相同值的序列减少为该值的单个实例。

所以我想要

a = [1, 1, 1, 2, 2, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3]

减少到

[1, 2, 3, 2, 3]

如您所见,Array#uniq 在这种情况下不起作用。

我有以下工作:

(a.size - 1).downto(1) { |i| a[i] = nil if a[i - 1] == a[i] }

谁能想出不那么难看的东西?

【问题讨论】:

    标签: ruby arrays


    【解决方案1】:

    对于最简单、最精简的解决方案,您可以使用方法Enumerable#chunk

    a.chunk(&:itself).map(&:first)
    

    itself 方法是 Ruby 2.2+。如果您卡在较旧的 Ruby 中,请使用 {|n| n},或者我的 backports gems。 它是在 Ruby 1.9.2 中引入的。如果您不幸使用较旧的 rubies,可以使用我的 backports gem 和 require 'backports/1.9.2/enumerable/chunk'

    【讨论】:

    • 你不需要x.first,你可以简单地说.map(&:first)
    • @DarkMouse 实际上你在 1.8.6 中做过 :-)。这在 4 年前是相关的,但在今天并不重要。我已经更新了答案
    • 从 Ruby 2.2 开始,a.chunk(&:itself).map(&:first) 可以工作并且看起来更好一些。
    【解决方案2】:
    a.inject([]){|acc,i| acc.last == i ? acc : acc << i }
    

    【讨论】:

    • 当我想起#inject 后,我也找到了这个。它肯定比我发布的尝试更干净,而且更“Rubyish”。 #chunk 的东西很难被击败,不过......
    【解决方案3】:

    我只能想到这个

    a.each_with_index{|item,i| a[i] = nil if a[i] == a[i+1] }.compact
    

    但或多或少是一样的。

    【讨论】:

      【解决方案4】:

      除非您非常关心块的计算速度,否则我建议您只需将此行添加到块的末尾即可获得所需的输出:

      a.compact!
      

      这只会删除您之前引入数组的所有 nil 元素(可能的重复项),形成您想要的输出:[1, 2, 3, 2, 3]

      如果你想要另一种算法,这里有比你的算法丑得多的东西。 :-)

      require "pp"
      
      a = [1, 1, 1, 2, 2, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3]
      
      i = 0
      
      while i < a.size do
        e = a[i]
        j = i
      
        begin
          j += 1
        end while e == a[j]
      
        for k in i+1..j-1 do
          a[k] = nil
        end
      
        i = j
      end
      
      pp a
      a.compact!
      pp a
      

      给你输出:

      [1, nil, nil, 2, nil, 3, nil, nil, nil, 2, nil, nil, 3, nil, nil]
      [1, 2, 3, 2, 3]
      

      在我看来,您的代码很好。只需添加 a.compact! 调用即可完成排序。

      【讨论】:

        【解决方案5】:

        另一种解决方案:

        acc = [a[0]]
        a.each_cons(2) {|x,y| acc << y if x != y}
        

        a.each_cons(2).inject([a[0]]) {|acc, (x,y)| x == y ? acc : acc << y}
        

        【讨论】:

        • 我似乎忘记了require 'enumerator',这通常是一个错误。我敢打赌,我可以在我的代码中找到十几个应该使用#each_cons 的地方。谢谢!
        【解决方案6】:

        如果数字都是 0-9 的单个数字:a.join.squeeze('0-9').each_char.to_a 应该可以工作。

        【讨论】:

        • 在我的情况下它们不是,但是如果我猴子补丁,你已经给了我方法的名称:Array#squeeze
        猜你喜欢
        • 1970-01-01
        • 2018-07-13
        • 1970-01-01
        • 2014-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多