如何将连续的相同元素推入子阵列?

时间:2014-05-09 09:38:35

标签: ruby-on-rails ruby ruby-1.8.7

例如,

input = ['a','b','b','b','a','a','b','c','c']

output = ['a',['b','b','b'],['a','a'],'b',['c','c']]

这里,如果有多个相同的元素,则将它们放入子数组中。

你能帮帮我吗?

3 个答案:

答案 0 :(得分:4)

此解决方案使用偷偷摸摸的技巧来防止必须检查列表元素是单个元素还是已经是数组。通过执行[*list[-1]],我们确保始终以数组结束,无论我们构建的list中的最后一个元素是否是单个元素(例如,'a')或数组已经(例如['b','b'])。然后,我们检查该数组的第一个元素(可能是任何元素,它们都是相同的)是否等于我们当前正在处理的input元素。如果是这样,我们将它附加到创建的数组。否则,我们只需将其附加到list,因为它与前一个元素不同。

input = ['a','b','b','b','a','a','b','c','c']

output = input.reduce([]) do |list, e|
  last = [*list[-1]]
  if last[0] == e
    list[-1] = last << e
  else
    list << e
  end
  list
end

p output
# ["a", ["b", "b", "b"], ["a", "a"], "b", ["c", "c"]]

或者,通过专门检查元素的类型,它将是这样的:

output = input.reduce([]) do |list, e|
  last = list.last
  if last.is_a? Array and last.include? e
    last << e
  elsif last == e
    list[-1] = [last, e]
  else
    list << e
  end
  list
end

这是在Ruby 2.0上测试的,但它也应该在1.8.7上正常运行。

答案 1 :(得分:4)

Ruby 1.9+有Enumerable#chunk,几乎可以满足您的需求:

input.
  chunk {|e| e }.
  map(&:last).
  map {|e| if e.size == 1 then e.first else e end }

对于旧版本的Ruby,Enumerable#chunk可用于Marc-AndréLafortunesbackports gem。只需添加

require 'backports/1.9.2/enumerable/chunk'

在上面。

答案 2 :(得分:0)

我的印象是,使用slice_before可以解决此问题。但无法理解。最后, Robert Klemme引导我朝着正确的方向前进。希望你们也喜欢它。

input = ['a','b','b','b','a','a','b','c','c']
prev = nil
input.slice_before { |e| (e != prev).tap { prev = e } }.
      map { |elem| elem.size == 1 ? elem.first : elem }
# => ["a", ["b", "b", "b"], ["a", "a"], "b", ["c", "c"]]