新手问题 这段代码有几个小细节不太理解,寻求帮助

drine · 2014年12月28日 · 最后由 Alexander 回复于 2014年12月31日 · 2562 次阅读

来自 rubykoans, about_scoring_project.rb 里的一个解法 (其中第 8 行 sum += 1000 | value -= 3 if value >= 3 的逻辑稍微有点小错误)

说明部分

  • dice 传入 3 个 1,1000 分
  • 3 个一样的其他数字,返回 100*其他数字(除了 3 个 1)
  • 一个 1 值 100 分
  • 一个 5 值 50 分
  • 其他都算 0 分

  • A set of three ones is 1000 points

  • A set of three numbers (other than ones) is worth 100 times the number. (e.g. three fives is 500 points).

  • A one (that is not part of a set of three) is worth 100 points.-

  • A five (that is not part of a set of three) is worth 50 points.

  • Everything else is worth 0 points.

## 我的问题是

  1. 想了解下这段代码是怎么达到上面的要求的..(主要是对于 if 里面的理解)
  2. inject 的 block 后面,分号后跟个 result 是什么意思啊?

* 还希望大神们能稍微详细的为小弟解决下这些问题。。做了一晚上的 rubykoans 了,都快昏了。。

def score(dice)
  return 0 if dice == []
  sum = 0
  rolls = dice.inject(Hash.new(0)) { |result, element| result[element] += 1; result; }
  rolls.each { |key, value| 
    # special condition for rolls of 1
    if key == 1  
      sum += 1000 | value -= 3 if value >= 3
      sum += 100*value
      next
    end
    sum += 100*key | value -= 3 if value >= 3
    sum += 50*value if key == 5 && value > 0
  }
  return sum
end

已经意识模糊了。。google 上搜到的代码又是如此模样,累觉不爱啊。。睡了明早再来看好了 = =

我也做过,我的答案是这个。好像是从哪里抄的了 http://www.51testing.com/index.php?uid-7844-action-viewspace-itemid-832538


def score(dice)
    s = 0
    dice.uniq.each do |x|
        array = dice.count(x).divmod(3)
        if 1 == x
            s += array[0] * 1000 + array[1] * 100
        elsif 5 == x
            s += array[0] * x * 100 + array[1] * 50
        else
            s += array[0] * x * 100
        end
    end
    s
end

#2 楼 @qqrrm 谢谢,但主要想了解下我贴的那段代码。 另外,记得以前 C 老师讲过,1 == x 比 x == 1 要好..但原因是啥来着呢?想不起了..囧

@drine 1 == x 一來可以避免寫出 1 = x (不小心少了一個等號) 的問題外,再看看以下這個有點極端的例子:

class Demo
  def ==(other)
    true
  end
end

obj = Demo.new

p obj == false  # true
p false == obj  # false

雖然平常沒事不會這樣搞,不過上面這樣的寫法的確會造成交換過來寫會得到不同的結果 :)

自己写,让测试一条一条通过,很简单的一道题,你贴的代码过于炫技,本来很简单的语句,非要别别扭扭的写出来

#5 楼 @cifery 是啊,too 炫酷 too 理解...。

对于写 1 == x , 而不是 x == 1, 原因是,第一个写法没有副作用,你知道你是在调用 1.==() 这个方法,如果你没有给 fixnum 做 monkey patch, 那么当且仅当参数确实为 1 时,函数返回 true, 再没有其他情况,如果写 x == 1, 你就要冒风险,因为你不知道 x 这个类的==方法是怎么定义的,极端一点就会有@eddle 提到的情况

#7 楼 @drine 安利给你一个 qq 群,1043776, 新手挺友好的,人也不多,但是不缺高手

#3 楼 @drine 其实就是避免把==写成=,导致判断语句变成赋值语句后,1=x 和 x=1 的区别就显而易见了,前者更安全。

def score(dice)
  return 0 if dice == []
  sum = 0
  # 遍历 dice,使其变成一个 Hash,key 为 dice 里面的数值,value 为 出现的次数
  # result 只的是 block 返回的值
  rolls = dice.inject(Hash.new(0)) { |result, element| result[element] += 1; result; }
  rolls.each { |key, value| 
    # special condition for rolls of 1
    if key == 1
      # 下面这句可以等价为
      # if value >= 3
      #   sum += 1000
      #   value -= 3
      # end
      # 这里的 `|` 无意义,不想写 begin end
      sum += 1000 | value -= 3 if value >= 3
      sum += 100*value
      next
    end
    sum += 100*key | value -= 3 if value >= 3
    sum += 50*value if key == 5 && value > 0
  }
  return sum
end

btw:这段代码性能不错,可惜是错误的,如果有 6 个 1 的话,它只会计入 1300 分。

12 楼 已删除

#11 楼 @Alexander 好多解法用 uniq,这个方法太耗时间了感觉

#11 楼 @Alexander 原题里没有要求处理 6 个 1 或者更多的情况,所以它那样写吧。不过还是有问题,在 stackoverflow 上有人帮忙修改了

#14 楼 @drine Sorry,我之前的理解错误,这里的 if 里面的 | 并非无意义,它的优先级比 += 要高,于是

sum += 1000 | value -= 3 if value >= 3

等价于

if value >= 3
  sum += (1000 | value -= 3)
end

| 操作符的意思是按位或,所以 sum 会得到一个不正确的值。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号