繁体   English   中英

迭代数组内的整数数字

[英]Iterate over digits of integers inside of array

我有以下代码:

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

需要考虑以下几点:

在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(:*)} a.map {|n| n.reduce(:*)}

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

挺好的!

所以,这个完整的解决方案比seph的单行程要长一点,事实上,如果我需要实际做某些事情,我只会to_s 我的解决方案执行速度更快吗? 谁知道? 但它肯定更具表现力,这就是你首先使用Ruby的原因。

如果你想解决问题,是的,绝对是, to_s 但是如果你希望你的代码能够表达一种关于数字的哲学,那么它们实际上也只是它们的集合 - 而且它们以一种奇怪的集理论方式,让你能够让它成为那样的。 而这种根本不需要字符串的方式,他们完全没有勉强的帮助。 并且你可以迭代不同的基础,如果你正在做十六进制或二进制,这是非常有用的,它保留了它们的更多数字本质。

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

您可以将其转换为字符串(.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] 

以下是修复代码的一种方法:

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! ,这将改变调用product的方法中a的值。 这可能也可能不行,但由于我正在返回计算值的数组,所以可能不行,所以我将应用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 <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 ; result结束了。

您可能会认为所有这些“改进”的最终结果是过于令人不安,或者作者只是炫耀。 这就是我刚认识Ruby时的想法。 但是,凭借经验,您会发现它非常自然,读起来像一个句子。 它还使调试更容易:从左到右工作,您可以测试链的每个链接,以确保它的工作。

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

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

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的答案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM