2009-02-24 41 views
8

摘要:这里的基本问题是,我发现,您是否可以将代码块传递给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} 

样本输出:

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 

注意几件事情:

  • 的条纹阵列具有交替的正和负值。
  • 元素条纹阵列的总和始终为0(这是原始的和)。
  • 连胜阵列的绝对值之和始终是20

希望是十分明显!

编辑:我也知道这样的构造为拒绝!实际上是在后台循环访问数组。我不排除循环,因为我是一个卑鄙的人。只是想了解这门语言。如果明确的迭代是必要的,那很好。

+0

为什么不遍历数组?您如何期望处理数组的内容而不循环。即使你使用一种方法来做到这一点,它仍然会在内部遍历数组。 – 2009-02-24 17:21:19

+0

你知道你在你的代码示例中调用的每个方法实际上是循环遍历数组... – kgrad 2009-02-24 17:22:50

+0

是的,没有办法在没有循环的情况下减少数组......没有办法访问内容。 – cdmckay 2009-02-24 17:25:16

回答

1

由于Ruby 1.9的还有一个更简单的解决这个问题的办法:

original_array.chunk{|x| x <=> 0 }.map{|a,b| a * b.size } 

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]]] 

这个几乎完全是OP所要求的,除非所得到的组需要计数以获得最终的条纹数组。

4
original_array.each do |num| 
    if streaks.size == 0 
    streaks << num 
    else 
    if !((streaks[-1] > 0)^(num > 0)) 
     streaks[-1] += 1 
    else 
     streaks << (num > 0 ? 1 : -1) 
    end 
    end 
end 

这里的魔法是^ xor运算符。

true^false #=> true 
true^true #=> false 
false^false #=> false 

因此,如果阵列中的最后一个数字是上的零作为被处理的数目相同的一侧,然后将其添加到条纹,否则将其添加到条纹阵列以开始一个新的条纹。请注意,正弦true^true返回false我们必须否定整个表达式。

11

嗯,这里是一个行版本,如果你高兴的话更多:

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

如果连注入太糊涂了你,这是一个非常愚蠢的方式:

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

但是我认为这是很清楚,你的东西更直接更好:

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

除了作为更容易理解和维护,在“循环”版本中约三分之二的运行时间的注入版本,约eval /正则表达式的六分之一的时间。

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} 

这使用两遍,首先构建条纹数组的数组,则数组的数组转换为签名大小的阵列。在Ruby 1.8.5中,这实际上比上面的注入版本稍快(尽管在Ruby 1.9中它稍慢),但无聊的循环仍然是最快的。

1

更多的字符串滥用,一拉格伦·麦克唐纳,只是不同:

runs = original_array.map do |e| 
    if e < 0 
    '-' 
    else 
    '+' 
    end 
end.join.scan(/-+|\++/).map do |t| 
    "#{t[0..0]}#{t.length}".to_i 
end 

p original_array 
p runs 
# => [2, 6, -4, 9, -8, -3, 1, 10, 5, -7, -1, 8, 7, -2, 4, 3, -5, -9, -10, -6] 
# => [2, -1, 1, -2, 3, -2, 2, -1, 2, -4]