迭代数组内的整数数字

时间:2013-10-10 03:52:02

标签: ruby arrays loops

我的代码如下:

 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一直在返回错误。

5 个答案:

答案 0 :(得分:5)

要考虑几点:

在Ruby中,你基本上不会使用for循环来迭代事物。 #each更好。你可以通过一个街区,为你提供各种灵活性和表现力的空间。

此外,你不能 - 通常 - 迭代Integer。请记住,Integer是一个数值存储,而不是特定的表示,因此它必须依赖于您想要的表示的基础。如果你想要一个字符串字符,每个字符都恰好是数字,那么,猜猜是什么?你想要一个String,就像这里的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。但是如果你希望你的代码能够表达一种关于数字的哲学,那么它们实际上也只是它们的集合 - 而且它们以一种奇怪的集理论方式,让你能够让它成为那样的。而这种根本不需要字符串的方式,他们完全没有勉强的帮助。你可以迭代不同的基础,如果你正在做十六进制或二进制,这是非常有用的,它保留了它们的更多数字本质。

在你和我一起建立的这个世界里,贾马尔,小整数与大男孩一起穿过森林。这太好了。

答案 1 :(得分: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] 

答案 2 :(得分: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

我们不需要上一个result,因为map!会返回result(以及更改result)。嘿,这也意味着我们可以只使用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&lt; 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

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

替换map
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

这里的注入参数是一个名为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时的想法。但是,凭借经验,您会发现它非常自然,读起来像一个句子。它还使调试更容易:从左到右工作,您可以测试链的每个链接,以确保它正常工作。

答案 3 :(得分:0)

a.collect{|x| 
  result = 1
  x.to_s.split('').each{|y| result *= y.to_i}
  result
}

答案 4 :(得分:0)

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

char buf[32];
snprintf(buf, 32, "%d %d", input.Z_pos_Camera_Temperature, input.Z_neg_Camera_Temperature);

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

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

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

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