我想在下面的数组中找到条纹的长度:
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
。
解决上述问题的优雅,高效和可读方式是什么?
这是一个递归问题吗?虽然我可以解决这个问题,但我觉得它暗示了一种我不熟悉的解决方法。它暗示也许这是通过递归最好地解决的问题。
(为了应用于此的“可能重复”标志的好处:两个线程实际上有不同的讨论。另外从搜索角度来看,如果搜索重复字符,你只能找到另一个线程,这就是答案如何检测重复的数组元素。最后这里有很多优秀的答案,删除这个问题不会让生态系统更富裕,只会更穷)
答案 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]