根据其中的条纹将Ruby数组块化

Ric*_*ong 8 ruby

简介:我发现,这里的基本问题是,您是否可以将代码块传递给Ruby数组,这实际上会将该数组的内容减少到另一个数组,而不是单个值(注入的方式).最简洁的答案是不".

我接受了这个说明的答案.感谢Squeegy提供了一个很好的循环策略来从阵列中获取条纹.

挑战:减少数组元素而不显式循环.
输入:从-10到10的所有整数(0除外)随机排序.
期望输出:表示正数或负数条纹的数组.例如,-3表示三个连续的负数.A 2代表两个连续的正数.

示例脚本:

original_array = (-10..10).to_a.sort{rand(3)-1}
original_array.reject!{|i| i == 0} # remove zero

streaks = (-1..1).to_a # this is a placeholder.  
# The streaks array will contain the output.
# Your code goes here, hopefully without looping through the array

puts "Original Array:"
puts original_array.join(",")
puts "Streaks:"
puts streaks.join(",")
puts "Streaks Sum:"
puts streaks.inject{|sum,n| sum + n}
Run Code Online (Sandbox Code Playgroud)

样本输出:

Original Array:
3,-4,-6,1,-10,-5,7,-8,9,-3,-7,8,10,4,2,5,-2,6,-1,-9
Streaks:
1,-2,1,-2,1,-1,1,-2,5,-1,1,-2
Streaks Sum:
0


Original Array:
-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,1,2,3,4,5,6,7,8,9,10
Streaks:
-10,10
Streaks Sum:
0
Run Code Online (Sandbox Code Playgroud)

请注意以下几点:

  • 条纹阵列具有交替的正值和负值.
  • 元素条纹数组的总和始终为0(原始值的总和).
  • 条纹数组的绝对值之和始终为20.

希望很清楚!

编辑:我确实意识到像拒绝这样的结构!实际上是在后台循环遍历数组.我不排除循环,因为我是一个卑鄙的人.只是想了解这门语言.如果需要显式迭代,那很好.

gle*_*ald 11

好吧,这是一个单行版本,如果这让你更满意:

streaks = original_array.inject([]) {|a,x| (a.empty? || x * a[-1] < 0 ? a << 0 : a)[-1] += x <=> 0; a}
Run Code Online (Sandbox Code Playgroud)

如果连注入对你来说都太环,那么这是一种非常愚蠢的方式:

  streaks = eval "[#{original_array.join(",").gsub(/((\-\d+,?)+|(\d+,?)+)/) {($1[0..0] == "-" ? "-" : "") + $1.split(/,/).size.to_s + ","}}]"
Run Code Online (Sandbox Code Playgroud)

但我认为很明显你会用更直接的东西做得更好:

streaks = []
original_array.each do |x|
  xsign = (x <=> 0)
  if streaks.empty? || x * streaks[-1] < 0
    streaks << xsign
  else
    streaks[-1] += xsign
  end
end
Run Code Online (Sandbox Code Playgroud)

除了更容易理解和维护之外,"循环"版本在注入版本的大约三分之二的时间内运行,并且大约是eval/regexp的六分之一.

PS:这是另一个可能有趣的版本:

a = [[]]
original_array.each do |x|
  a << [] if x * (a[-1][-1] || 0) < 0
  a[-1] << x
end
streaks = a.map {|aa| (aa.first <=> 0) * aa.size}
Run Code Online (Sandbox Code Playgroud)

这使用两次传递,首先构建一个条纹数组数组,然后将数组数组转换为有符号大小的数组.在Ruby 1.8.5中,这实际上比上面的注入版本略快(虽然在Ruby 1.9中它稍微慢一点),但是无聊的循环仍然是最快的.


Sar*_*Mei 6

new_array = original_array.dup
<Squeegy's answer, using new_array>
Run Code Online (Sandbox Code Playgroud)

塔达!没有循环遍历原始数组.虽然在里面复制它是一个MEMCPY,我想这可能被认为是汇编程序级别的循环?

http://www.ruby-doc.org/doxygen/1.8.4/array_8c-source.html

编辑: ;)


use*_*234 1

从 Ruby 1.9 开始,有一种更简单的方法来解决这个问题:

original_array.chunk{|x| x <=> 0 }.map{|a,b| a * b.size }
Run Code Online (Sandbox Code Playgroud)

Enumerable.chunk将通过块的输出将数组的所有连续元素分组在一起:

>> original_array.chunk{|x| x <=> 0 }
=> [[1, [3]], [-1, [-4, -6]], [1, [1]], [-1, [-10, -5]], [1, [7]], [-1, [-8]], [1, [9]], [-1, [-3, -7]], [1, [8, 10, 4, 2, 5]], [-1, [-2]], [1, [6]], [-1, [-1, -9]]]
Run Code Online (Sandbox Code Playgroud)

这几乎正​​是OP所要求的,除了需要对结果组进行计数以获得最终的条纹数组。