正数/负数之和语法错误

时间:2016-11-15 23:28:13

标签: ruby algorithm

所以我目前正在处理代码大战中的以下问题:

返回一个数组,其中第一个元素是正数的数量,第二个元素是负数的总和。如果输入数组为空或null,则返回一个空数组。

我提出了以下代码,它很不错,但我知道它应该可行:

def count_positives_sum_negatives(lst)
  pos, neg = 0, 0

  lst.each do |num|
    if num < 0
      neg += num
    else
      pos++
    end
  end

  [pos, neg]
end

然后我调用以下测试:

count_positives_sum_negatives([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, -12, -13, -14, -15])

它应该返回=&gt; [10,-65]

然而它返回以下错误:

(repl):11: syntax error, unexpected keyword_end
(repl):17: syntax error, unexpected end-of-input, expecting keyword_end
..., 10, -11, -12, -13, -14, -15])
...       

有人能解释一下为什么会这样吗?

5 个答案:

答案 0 :(得分:7)

正如人们已经指出这里的错误是x++不是有效的Ruby,你需要x +=1。后缀和前缀增量运算符在大多数语言中都是一个混乱的点,因此Ruby从未实现过。同样,x++ + x++ + ++x的结果是什么?

使用partition首先拆分数组,然后使用inject将其折叠在一起,这是一个不同的策略:

positives, negatives = list.partition(&:positive?)

[ positives.length, negatives.inject(0, &:+) ]
# => [10,-65]

答案 1 :(得分:4)

这是你可以做到的另一种方式。

def count_pos_sum_neg(arr)
  return [] if arr.empty?
  arr.each_with_object([0,0]) do |n,a|
    a[0] += 1 if n > 0
    a[1] += n if n < 0
  end
end

count_pos_sum_neg [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, -12, -13, -14, -15]
  #=> [10, -65]

在实际应用中,返回哈希可能更方便。

def count_pos_sum_neg(arr)
  return [] if arr.empty?
  arr.each_with_object({count_pos: 0, sum_neg: 0}) do |n,h|
    h[:count_pos] += 1 if n > 0
    h[:sum_neg]   += n if n < 0
  end
end

count_pos_sum_neg [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, -12, -13, -14, -15]
  #=> {:count_pos=>10, :sum_neg=>-65} 

答案 2 :(得分:2)

问题是pos++,这不是Ruby中的有效操作。它被解释为一个加法后跟一元+,但是在一元之后没有数字,所以它期望下一行包含一个值。

但下一行是end,这是意外的(因此是第一个错误unexpected keyword_end),因为现在消耗了end,你错过了方法的结束(因此第二行)错误expecting keyword_end

所以只需将行改为......

pos += 1

答案 3 :(得分:1)

另一种使用inject的变体:

def count_pos_sum_neg(arr)
  arr.inject([0, 0]) do |(count, sum), n|
    if n > 0
      [count + 1, sum]
    else
      [count, sum + n]
    end
  end
end

或压缩:

def count_pos_sum_neg(arr)
  arr.inject([0, 0]) { |(c, s), n| n > 0 ? [c + 1, s] : [c, s + n] }
end

代码不检查“如果输入数组为空或为空”。

答案 4 :(得分:0)

我怀疑你最初的方法很容易阅读和简单,实际上也很快。 fruity比较(代码压缩)的一些结果:

require 'fruity'

arr = ((-1000..-1).to_a + (1..1000).to_a).shuffle

#various methods etc as defined in other answers.

compare do
  wnamen  { ar = arr; wnamen_method ar  }
  tadman  { ar = arr; tadman_method ar  }
  cary    { ar = arr; cary_method ar    }
  cary2   { ar = arr; cary2_method ar   }
  stefan  { ar = arr; stefan_method ar  }
  stefan2 { ar = arr; stefan2_method ar }
end

结果:

Running each test 8 times. Test will take about 1 second.
wnamen is faster than tadman by 2.0x ± 0.1
tadman is similar to stefan2
stefan2 is similar to stefan
stefan is similar to cary
cary is faster than cary2 by 19.999999999999996% ± 10.0% (results differ: [1000, -500500] vs {:count_pos=>1000, :sum_neg=>-500500})

所有其他方法当然都很有趣,但仍然值得了解。