查找数组

时间:2016-02-06 21:16:00

标签: ruby algorithm

我想在下面的数组中找到条纹的长度:

states = [:read, :read, :read, :unread, :unread, :read, :read, :read, :read]

数组有:read:unread,我希望每个条纹的长度为:read / :unread。对于states,这将成为:

streak_lengths = [3, 3, 3, 2, 2, 4, 4, 4, 4]

数组以三个:read元素打开,我们将每个元素标记为3条纹的一部分,然后它有两个:unread元素,因此它们都被标记带有2条纹,最后我们有四条读取消息,因此它们都标有4

解决上述问题的优雅,高效和可读方式是什么?

这是一个递归问题吗?虽然我可以解决这个问题,但我觉得它暗示了一种我不熟悉的解决方法。它暗示也许这是通过递归最好地解决的问题。

(为了应用于此的“可能重复”标志的好处:两个线程实际上有不同的讨论。另外从搜索角度来看,如果搜索重复字符,你只能找到另一个线程,这就是答案如何检测重复的数组元素。最后这里有很多优秀的答案,删除这个问题不会让生态系统更富裕,只会更穷)

4 个答案:

答案 0 :(得分:7)

chunk分段为数组连续元素,当对它们调用块时,它们具有相同的返回值。 flat_map将块返回的数组连接成一个数组。

states.chunk(&:itself).flat_map{|_, a| Array.new(a.length, a.length)}
# => [3, 3, 3, 2, 2, 4, 4, 4, 4]

如果你愿意,也许你可以以递归的方式做到,但我认为这不会导致优雅的解决方案。根据我的经验,最好尽可能避免递归。

答案 1 :(得分:5)

使用Ruby v2.2

states.slice_when { |a,b| a != b }.flat_map { |a| [a.size]*a.size }
  #=> [3, 3, 3, 2, 2, 4, 4, 4, 4]

使用Ruby v2.3

states.chunk_while { |a,b| a == b }.flat_map { |a| [a.size]*a.size }
  #=> [3, 3, 3, 2, 2, 4, 4, 4, 4] 

但这些都不比普通的chunk提供任何优势。

答案 2 :(得分:2)

这实际上是最简单的压缩算法所做的,在这种情况下,它简称为行程编码或RLE。

RosettaCode's Wiki Page on RLE

上找到了一些关于如何在Ruby中实现RLE的Ruby示例

关于你的问题的最相关的例子可能是第一个:

# run_encode("aaabbbbc") #=> [["a", 3], ["b", 4], ["c", 1]]
def run_encode(string)
  string
    .chars
    .chunk{|i| i}
    .map {|kind, array| [kind, array.length]}
end

这使用了Ruby自己的Enumerator类中的chunk方法,该方法对于您可以枚举的类很常见,例如Arrays和Hashes。它枚举项目,根据块的返回值将它们组合在一起。

从示例中学习,我们可以使用以下代码获取您要求的输出类型(从@sawa的答案中借用flat_map用法,因为我的实际上并没有从[:read,]返回[2,2]:阅读]但只有2):

states = [:read, :read, :read, :unread, :unread, :read, :read, :read, :read]
states.chunk{|a| a}.flat_map{|_, a| [a.length] * a.length}
# outputs [3, 3, 3, 2, 2, 4, 4, 4, 4]

答案 3 :(得分:0)

所有好的答案都已经发布了,因此,我发布了另一种方法来实现这一点 - 如果数组元素是对另一个现有数组的引用,它会利用这一事实,然后,对所有人都可以看到对现有数组的修改引用它的元素。

例如:

a = [1]
b = [a, a, a, a]
#=> [[1], [1], [1], [1]]
a[0] = 2
b
#=> [[2], [2], [2], [2]]
states = [:read, :read, :read, :unread, :unread, :read, :read, :read, :read]

t = [1]
result = []
states.each_with_index do |ele, i|
  result[i] = t
  if i + 1 < states.size and states[i+1] == states[i]
    result[i][0] += 1
  else
    t = [1] 
  end
end

p result.flatten
#=> [3, 3, 3, 2, 2, 4, 4, 4, 4]