代码之家  ›  专栏  ›  技术社区  ›  Mike Woodhouse

移除Ruby数组中相邻的相同元素?

  •  10
  • Mike Woodhouse  · 技术社区  · 15 年前

    红宝石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] }
    

    有人能想出不那么难看的东西吗?

    6 回复  |  直到 6 年前
        1
  •  21
  •   Marc-André Lafortune    6 年前

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

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

    这个 itself 方法是Ruby 2.2+。使用 {|n| n} 如果你困在一颗老红宝石里,或者我的 backports 宝石。 它是在Ruby1.9.2中引入的。如果你不走运,用老红宝石,你可以用我的背部宝石和 require 'backports/1.9.2/enumerable/chunk' .

        2
  •  5
  •   Mladen Jablanović    15 年前
    a.inject([]){|acc,i| acc.last == i ? acc : acc << i }
    
        3
  •  1
  •   dimitarvp    15 年前

    除非你是 非常 考虑到块的计算速度,我建议您将这一行添加到块的末尾,以获得所需的输出:

    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! 打电话,你就被分类了。

        4
  •  1
  •   glenn jackman    15 年前

    另一个解决方案:

    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}
    
        5
  •  1
  •   jco    15 年前

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

        6
  •  0
  •   Draco Ater    15 年前

    我只能想到这个

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

    但或多或少是一样的。