2

我在下面有这段代码:

 a = [435,276,434]

 def product(a)
   final = 1
   for e in a
     for p in a[e]
       final*=p
     end
   end
   final
 end

 puts product(a)

我想知道如何迭代这个数组两次,结果是 4*3*5 = 60、2*7*6 = 85 和 4*3*4 = 48

我在上面写了一些我认为可以在这里解决问题的代码,但是 Ruby 不断返回错误。

4

5 回答 5

5

需要考虑的几点:

在 Ruby 中,您基本上从不使用for循环来迭代事物。#each更好。你可以通过一个障碍,这给你各种灵活性和表现力的空间。

此外,您不能 - 通常 - 迭代Integer. 请记住,整数是数值的存储,而不是特定的表示,因此它必须取决于您想要的表示的基础。如果你想要一串字符,每个字符恰好是数字,那么你猜怎么着?你想要一个String, like seph 的解决方案。或者一个Array,这可能更有意义,因为每个整数都将保持一个整数,并且不必来回解析。

告诉你什么,让我们构建一个非常酷的方法来执行此操作并将其钉在 Integer 上,并希望展示 Ruby 的一些很酷的特性。

class Integer
  include Enumerable
  def each(base = 10, &blk)
    front, back = abs.divmod(base)
    if front > 0
      front.each(base, &blk)
    end
    yield back
  end
end

这个小数字需要一个基数和一个块,得到整数的绝对值(因为从技术上讲,减号不是数字),然后使用 divmod 拆分数字,去掉最后一个数字。我们将碎片存放在前后。我们检查是否还有更多数字,前面为 0 表示,如果有,我们使用该块递归调用此方法。然后我们只是让步,将数字发送到块。

由于我们现在已经定义了一个each方法,我们现在可以自由地包含Enumerable它,它可以为我们带来大量的东西!

只要该修改处于活动状态,您的product方法就会变为:

(如果你想打印 60 84 48):a.map {|n| n.reduce(:*)}

(或者如果你想打印 241920):a.reduce(:*).reduce(:*)

挺棒的!

所以,这个完整的解决方案比 seph 的单线解决方案要长得多,事实上,如果我需要真正做一些事情,我只会to_s. 我的解决方案执行起来更快吗?谁知道?不过,它肯定更具表现力,这就是您首先使用 Ruby 的原因。

如果你想解决一个问题,是的,绝对的,to_s。但是如果你想让你的代码表达你对数字的哲学,关于它们实际上也只是集合——它们是,以一种奇怪的集合论的方式,Ruby 让你赋予它们这样的能力。这种方式根本不需要字符串,他们完全没有勉强的帮助。而且您可以遍历不同的基础,如果您使用十六进制或二进制,这将非常有用,这样可以保留它们更多的数字本质。

在你我共同建立的这个世界里,贾马尔,小家伙们和大男孩们一起在森林里狂奔。这太棒了。

于 2013-10-10T05:32:56.723 回答
4

您可以将其转换为字符串(.to_s)。然后很容易将每个数字作为char(.chars),将它们转换回整数(.map(&:to_i)) 并将它们相乘(.reduce(:*))

a = [435,276,434]
a.map {|n| n.to_s.chars.map(&:to_i).reduce(:*) }
=> [60, 84, 48] 
于 2013-10-10T04:26:18.353 回答
3

这是修复代码的一种方法:

a = [435,276,434]

def product(a)
  result = [] # Create an empty array that will become [60, 85, 48]
  for e in a
    final = 1
    # Convert the integer e to a string (e.g., "435")
    str = e.to_s
    # Iterate over each char of the string (e.g., "4", "3" and "5")
    str.each_char do |c|
      # Convert the character 'c' to an integer (digit) then multiply final by that integer          
      final *= c.to_i
    end    
    # Append the value of final to the result array
    result << final # e.g., when result = [60], result << 85 => [60, 85]
  end
  result # => [60, 85, 48]
end

product(a) # => [60, 85, 48]

现在让我们看看如何改进它。首先,我们可以链接操作并避免使用临时变量str。此外,您会发现 for 循环each通常比for(尤其是因为您可以使用带有 的块each)更可取,所以我也会对其进行更改。当我这样做时,由于each_char循环只包含一个语句,我将用括号而不是do/end. 我们现在有:

def product(a)
  result = [] # Create an empty array that will become [60, 85, 48]
  a.each do |e|
    final = 1
    e.to_s.each_char {|c| final *= c.to_i}
    result << final
  end
  result
end

当我看到这个时,我想我想将数组的每个元素转换a为其他元素(其数字的乘积)。这表明使用Array方法map!(或其同义词,collect!),而不是each。由于a是方法的参数product,如果我使用a.map!,那将改变a调用方法中的值product。这可能好也可能不好,但由于我返回的是一个计算值数组,所以可能不好,所以我将map!申请a. (它被称为“浅”副本,这在这里并不重要,但在其他情况下也可以。)我们现在有这个:

def product(a)
  result = a.dup
  result.map! do |e|
    final = 1
    e.to_s.each_char {|c| final *= c.to_i}
    final
  end
  result
end

我们不需要 last result,因为map!返回result(以及改变result)。嘿,这也意味着我们可以使用just map(没有区别)。此外,我们可以链接a.dupmap摆脱result

def product(a)
  a.dup.map do |e|
    final = 1
    e.to_s.each_char {|c| final *= c.to_i}
    final
  end
end

伙计,我们正在用煤气做饭!接下来,每当您看到一个计算某物的乘积或总和的块时,请思考inject(或其同义词,reduce):

def product(a)
  a.dup.map do |e|
    e.to_s.each_char.inject(1) {|final, c| final * c.to_i}
  end
end

假设a< 0。怎么办?(@Leon 的回答让我想到了这种可能性。)否定的接收者对 没有意义each,所以如果发生这种情况,让我们提出一个例外:

def product(a)
  raise RuntimeError, "Receiver must be non-negative" if self < 0
  a.dup.map do |e|
    e.to_s.each_char.inject(1) {|final, c| final * c.to_i}
  end
end

你可能想在这里停下来,但你可以map用另一个 `inject:

def product(a)
  raise RuntimeError, "Receiver must be non-negative" if self < 0
  a.inject([]) {|result, e| result.concat.e.to_s.each_char.inject(1) {|final, c| final * c.to_i}}
end

在这里,inject 的参数是一个名为 的空数组result。请注意,由于我们没有更改a,我们不再需要dup. (我看到@Kingston 得到了类似的答案。)如果你愿意,你可以这样写:

def product(a)
  raise RuntimeError, "Receiver must be non-negative" if self < 0
  a.inject([]) {|result, e| result << e.to_s.each_char.inject(1) {|final, c| final * c.to_i}; result}
end

但请注意需要那个讨厌; result的结尾。

您可能会认为所有这些“改进”的最终结果太过分了,或者作者只是在炫耀。这就是我刚接触 Ruby 时的想法。然而,随着经验,你会发现它很自然,读起来像一个句子。它还使调试更容易:从左到右工作,您可以测试链的每个环节以确保其正常工作。

于 2013-10-10T06:12:21.847 回答
0
a.collect{|x| 
  result = 1
  x.to_s.split('').each{|y| result *= y.to_i}
  result
}
于 2013-10-10T05:33:14.563 回答
0

如果意图只是迭代数字,您也可以使用字符串切片方法。

num = a[0].to_s # "435" 
final = num[0,1].to_i * num[1,1].to_i * num[2,1].to_i #4*3*5

或者

final = num[0..1].to_i * num[1..2].to_i * num[2..3].to_i

对于给定的问题,如果您知道它是一个每个 3 位数字的数组,那么您可以跳过内部循环,解决方案可能是这样的:

a = [435,276,434]

def product(a)
    a.map! do |digits|
        final = 1
        num = digits.to_s
        final = num[0,1].to_i * num[1,1].to_i * num[2,1].to_i
    end
end

puts product(a).inspect

该答案仅针对上述问题。由于它操作相同的数组,因此它编辑接收器。有关更详细和完整的解决方案,请查看 Cary Swoveland 的答案。

于 2017-06-08T15:58:21.590 回答