ruby-on-rails - ruby on rails - 在数组中,如何计算连续数?

如果我有一个数组:

 

array = [1,2,2,2,2,5,5,1,1,1,3,3,3,3,2,2,2,2,2,2,2]



我想能够识别连续匹配的数字,它长度大于3,并映射连续数的起始索引,上述数组的示例输出为:

 

consecutive_numbers = [


 {starting_index: 1, value: 2, length: 4},


 {starting_index: 10, value: 3, length: 4},


 {starting_index: 14, value: 2, length: 7}


]



值可以是相同的,但是,连续序列必须是互斥的,看到有2个哈希值为2,但是,它们的起始索引是不同的。

我目前的尝试,看起来像这样:

 

array.each_cons(3).with_index.select{|(a,b,c), i| 


 [a,b,c].uniq.length == 1


}



但这将会返回:

 

[[[2, 2, 2], 1], [[2, 2, 2], 2], [[1, 1, 1], 7], [[3, 3, 3], 10], [[3, 3, 3], 11], [[2, 2, 2], 14], [[2, 2, 2], 15], [[2, 2, 2], 16], [[2, 2, 2], 17], [[2, 2, 2], 18]]



但这将返回重叠的结果。

时间:

 

array.each_with_index.


 chunk(&:first).


 select { |_,a| a.size> 3 }.


 map { |n,a| { starting_index: a.first.last, value: n, length: a.size } }


 #=> [{:starting_index=> 1, :value=>2, :length=>4},


 # {:starting_index=>10, :value=>3, :length=>4},


 # {:starting_index=>14, :value=>2, :length=>7}] 



这些步骤如下所示。

 

e = array.each_with_index.chunk(&:first)


 #=> #<Enumerator: #<Enumerator::Generator:0x00005b1944253c18>:each> 



我们可以将这个枚举数转换为一个数组来查看它将生成的元素,并且传递给它的块。

 

e.to_a


 #=> [[1, [[1, 0]]],


 # [2, [[2, 1], [2, 2], [2, 3], [2, 4]]],


 # [5, [[5, 5], [5, 6]]],


 # [1, [[1, 7], [1, 8], [1, 9]]],


 # [3, [[3, 10], [3, 11], [3, 12], [3, 13]]],


 # [2, [[2, 14], [2, 15], [2, 16], [2, 17], [2, 18], [2, 19], [2, 20]]]] 



继续

 

c = e.select { |_,a| a.size> 3 }


 #=> [[2, [[2, 1], [2, 2], [2, 3], [2, 4]]],


 # [3, [[3, 10], [3, 11], [3, 12], [3, 13]]],


 # [2, [[2, 14], [2, 15], [2, 16], [2, 17], [2, 18], [2, 19], [2, 20]]]] 


c.map { |n,a| { starting_index: a.first.last, value: n, length: a.size } }


 #=> [{:starting_index=> 1, :value=>2, :length=>4},


 # {:starting_index=>10, :value=>3, :length=>4},


 # {:starting_index=>14, :value=>2, :length=>7}] 



这是另一种方法。

 

array.each_with_index.with_object([]) do |(n,i),arr|


 if arr.any? && arr.last[:value] == n


 arr.last[:length] += 1


 else


 arr < <{ starting_index: i, value: n, length: 1 }


 end


end.select { |h| h[:length]> 3 }


 #=> [{:starting_index=> 1, :value=>2, :length=>4},


 # {:starting_index=>10, :value=>3, :length=>4},


 # {:starting_index=>14, :value=>2, :length=>7}] 



你可以将每对元素都视为相等:

 

p array.chunk_while { |a, b| a == b }.to_a


# [[1], [2, 2, 2, 2], [5, 5], [1, 1, 1], [3, 3, 3, 3], [2, 2, 2, 2, 2, 2, 2]]



选择包含3个或更多元素的数组。

之后,通过then,你可以获得自己,因此你可以访问数组数组,这些数组可用于获取 starting_index

 

[1,2,2,2,2,5,5,1,1,1,3,3,3,3,2,2,2,2,2,2,2].chunk_while(&:==).then do |this|


 this.each_with_object([]).with_index do |(e, memo), index|


 memo < <{ starting_index: this.to_a[0...index].flatten.size, value: e.first, length: e.size }


 end


end.select { |e| e[:length]> 3 }



# [{:starting_index=>1, :value=>2, :length=>4},


# {:starting_index=>10, :value=>3, :length=>4},


# {:starting_index=>14, :value=>2, :length=>7}]



对于starting_index,将元素获取到当前索引(非包含),平整它们,并获取元素的总数。

如果数组中的每个数组都具有相同的元素,则长度为"main"数组中当前数组的长度。

这是另一个选择。

 

array


 . zip(0..)


 . slice_when { |a, b| a.first!= b.first }


 . map { |a| { starting_index: a.first.last, value: a.first.first, length: a.size } }


 . reject { |h| h[:length] <3 }



#=> [{:starting_index=>1, :value=>2, :length=>4}, {:starting_index=>7, :value=>1, :length=>3}, {:starting_index=>10, :value=>3, :length=>4}, {:starting_index=>14, :value=>2, :length=>7}]



最明显的(可能是最快的)方法是遍历数组,并且手工计数所有内容:

 

array = [1,2,2,2,2,5,5,1,1,1,3,3,3,3,2,2,2,2,2,2,2]


array_length_pred = array.length.pred



consecutive_numbers = []



starting_index = 0


value = array.first


length = 1



array.each_with_index do |v, i|


 if v!= value || i == array_length_pred


 length += 1 if i == array_length_pred && value == v



 if length> = 3


 consecutive_numbers < <{


 starting_index: starting_index,


 value: value,


 length: length


 }


 end



 starting_index = i


 value = v


 length = 1


 next


 end



 length += 1


end



p consecutive_numbers



# [{:starting_index=>1, :value=>2, :length=>4},


# {:starting_index=>7, :value=>1, :length=>3},


# {:starting_index=>10, :value=>3, :length=>4},


# {:starting_index=>14, :value=>2, :length=>7}]



你可以用字符串代替。

在这里,我将数组强制为字符串:

 

input_sequence = [1,2,2,2,2,5,5,1,1,1,3,3,3,3,2,2,2,2,2,2,2].join



我使用正规表达式对连续字符进行分组:

 

groups = input_sequence.gsub(/(.)1*/).to_a


#=> [" 1" ," 2222" ," 55" ," 111" ," 3333" ," 2222222" ]



现在,我可以在输入字符串中将组作为子字符串进行搜索:

 

groups.map do |group|


 {


 starting_index: input_sequence.index(group), 


 value: group[0].to_i,


 length: group.length


 }


end.reject { |group| group[:length] <= 3 }



#=> [{:starting_index=>1, :value=>2, :length=>4},


 {:starting_index=>7, :value=>1, :length=>3},


 {:starting_index=>10, :value=>3, :length=>4},


 {:starting_index=>14, :value=>2, :length=>7}]



...