简体   繁体   English

迭代数组内的整数数字

[英]Iterate over digits of integers inside of array

I have this code below: 我有以下代码:

 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)

I'm wondering how I can iterate over this array twice where the result is 4*3*5 = 60, 2*7*6 = 85, and 4*3*4 = 48 我想知道如何迭代这个数组两次,结果是4 * 3 * 5 = 60,2 * 7 * 6 = 85,和4 * 3 * 4 = 48

I wrote some code up above which I thought would do the trick here but Ruby keeps on returning an error. 我在上面编写了一些代码,我认为这样可以解决这个问题,但是Ruby一直在返回错误。

A few points to consider: 需要考虑以下几点:

In Ruby you basically never use a for loop to iterate over things. 在Ruby中,你基本上不会使用for循环来迭代事物。 #each is better. #each更好。 You get to pass a block to that, which gives you all kinds of room for flexibility and expressiveness. 你可以通过一个街区,为你提供各种灵活性和表现力的空间。

Also, you can't - normally - iterate over an Integer . 此外,您不能 - 通常 - 迭代Integer Remember that an Integer is a store of numerical value, not a particular representation, so it would have to be dependent on the base of the representation you wanted. 请记住,Integer是一个数值存储,而不是特定的表示,因此它必须依赖于您想要的表示的基础。 If you want a string of characters, each of which happen to be numbers, well, guess what? 如果你想要一串字符,每个字符恰好都是数字,那么猜猜是什么? You want a String , like seph's solution here. 你想要一个String ,就像这里的seph解决方案一样。 Or an Array , which would probably make even more sense because each integer would remain an integer and wouldn't have to be parsed back and forth. 或者一个Array ,这可能会更有意义,因为每个整数都将保持整数,并且不必来回解析。

Tell you what, let's build a really cool method to do this and staple this on to Integer, and hopefully demonstrate some of Ruby's cool features. 告诉你什么,让我们构建一个非常酷的方法来实现这一点并将其主要用于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

This little number takes a base and a block, gets the absolute value of the integer (since technically the minus isn't a digit), then uses divmod to split the number, chopping off the final digit. 这个小数字取一个基数和一个块,得到整数的绝对值(因为从技术上讲,减号不是一个数字),然后用divmod分割数字,砍掉最后一个数字。 We store the pieces in front and back. 我们将这些碎片存放在前后。 We check to see if there are any more digits, indicated by front being 0, and if there is we recursively call this method, with that block. 我们检查是否有更多的数字,由前面0表示,如果我们以递归方式调用此方法,则使用该块。 Then we just yield the back, sending the digit to the block. 然后我们只是屈服于后面,将数字发送到块。

Since we have now defined an each method, we are now free to include Enumerable which gets us a ton of stuff! 既然我们现在已经定义了each方法,我们现在可以自由地包含Enumerable ,它可以为我们提供大量的东西!

As long as that modification is active, your product method becomes: 只要该修改处于活动状态,您的product方法就变为:

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

(or if you wanted to print 241920): a.reduce(:*).reduce(:*) (或者如果你想打印241920): a.reduce(:*).reduce(:*)

Pretty nice! 挺好的!

So, this total solution is quite a bit longer than seph's one-liner, and in truth if I needed to actually do something I would just to_s . 所以,这个完整的解决方案比seph的单行程要长一点,事实上,如果我需要实际做某些事情,我只会to_s Is my solution quicker to execute? 我的解决方案执行速度更快吗? Who knows? 谁知道? It's certainly more expressive, though, and that's why you're using Ruby in the first place. 但它肯定更具表现力,这就是你首先使用Ruby的原因。

If you want to solve a problem, yeah, absolutely, to_s . 如果你想解决问题,是的,绝对是, to_s But if you want your code to express a philosophy you have about numbers, about how really they're just collections too - and they are, in a weird set theory kind of way, Ruby lets you empower them to be that. 但是如果你希望你的代码能够表达一种关于数字的哲学,那么它们实际上也只是它们的集合 - 而且它们以一种奇怪的集理论方式,让你能够让它成为那样的。 And this way that doesn't need Strings at all, they're totally free of their grudging assistance. 而这种根本不需要字符串的方式,他们完全没有勉强的帮助。 And you can iterate through different bases, which is super useful if you're doing hex or binary, which preserves more of the numbery essence of them. 并且你可以迭代不同的基础,如果你正在做十六进制或二进制,这是非常有用的,它保留了它们的更多数字本质。

In this world that you and I have built together, Jamaal, little integers run wild through the forests with the big boys. 在你和我一起建立的这个世界里,贾马尔,小整数与大男孩一起穿过森林。 And that's wonderful. 这太好了。

You could convert it to a string(.to_s). 您可以将其转换为字符串(.to_s)。 Then it's easy to get each digit as a char(.chars), convert them back to an integers(.map(&:to_i)) and multiply them together(.reduce(:*)) 然后很容易将每个数字作为char(.chars),将它们转换回整数(.map(&:to_i))并将它们相乘(.reduce(:*))

a = [435,276,434]
a.map {|n| n.to_s.chars.map(&:to_i).reduce(:*) }
=> [60, 84, 48] 

Here's one way you could fix your code: 以下是修复代码的一种方法:

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]

Now let's see how we can improve it. 现在让我们看看我们如何改进它。 Firstly, we can chain operations and avoid the use of the temporary variable str . 首先,我们可以链接操作并避免使用临时变量str Also, you'll find that for loops, each is generally preferable to for (especially because you can use a block with each ), so I'll change that too. 此外,你会发现for循环, each通常都是优选for (特别是因为你可以使用each块),所以我也会改变它。 While I'm at it, since the each_char loop contains only one statement, I'll write the block with brackets rather than do/end . 虽然我在它,因为each_char循环只包含一个语句,我将用括号而不是do/end编写块。 We now have: 我们现在有:

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

When I look at this, I'm thinking I want to convert each element of the array a to something else (the product of its digits). 当我看到这个时,我想我想将数组a每个元素转换为其他东西(其数字的乘积)。 That suggests the use of the Array method map! 这表明使用了Array方法map! (or its synonym, collect! ), rather than each . (或其同义词, collect! ),而不是each Since a is the argument of the method product , if I use a.map! 由于a是方法product的参数,如果我使用a.map! , that will change the values of a in the method that calls product . ,这将改变调用product的方法中a的值。 That may or may not be OK, but since I'm returning an array of the computed values, it's probably not OK, so I'll apply map! 这可能也可能不行,但由于我正在返回计算值的数组,所以可能不行,所以我将应用map! to a copy of a . 到副本a (It's called a "shallow" copy, which is not important here, but can be in other situations.) We now have this: (它被称为“浅层”副本,这在这里并不重要,但可以在其他情况下使用。)我们现在有:

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

We don't need the last result , because map! 我们不需要最后的result ,因为map! returns result (as well as changing result ). 返回result (以及更改result )。 Hey, that also means we can use just map (makes no difference). 嘿,这也意味着我们可以只使用map (没有区别)。 Also, we can chain a.dup and map to get rid of result : 此外,我们可以链接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

Man, we're cookin' with gas! 伙计,我们用煤气做饭! Next, whenever you see a block that computes the product or sum of something, think inject (or its synomym, reduce ): 接下来,每当您看到计算产品或某事物总和的块时,请考虑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

Suppose a < 0. What to do? 假设a <0怎么办? (@Leon's answer twigged me to that possibility.) A negative receiver makes no sense to each , so let's raise an exception if that happens: (@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

You may want to stop here, but you could replace map with another `inject: 你可能想停在这里,但你可以用另一个`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

Here the argument for inject is an empty array called result . 这里的注入参数是一个名为result的空数组。 Notice that, since we haven't changed a , we no longer needed dup . 请注意,由于我们没有更改a ,因此我们不再需要dup (I see @Kingston arrived at a similar answer.) If you prefer, you could write this as: (我看到@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

but notice the need for that pesky ; result 但请注意那个讨厌的需要; result ; result an the end. ; result结束了。

You might think that the end result of all these "improvements" is too much of a mind-bender, or that the author is just showing off. 您可能会认为所有这些“改进”的最终结果是过于令人不安,或者作者只是炫耀。 That's what I thought when I was new to Ruby. 这就是我刚认识Ruby时的想法。 With experience, however, you will find it is very natural and reads like a sentence. 但是,凭借经验,您会发现它非常自然,读起来像一个句子。 It also makes debugging easier: working left-to-right, you can test each link of the chain to make sure it's working. 它还使调试更容易:从左到右工作,您可以测试链的每个链接,以确保它的工作。

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

If the intent is to just iterate over the digits, you can use the string slice methods too. 如果意图是迭代数字,您也可以使用字符串切片方法。

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

or 要么

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

For the given question, if you know it is an array of 3 digits each, then you can skip the inner loop and the solution could be like this: 对于给定的问题,如果你知道它是一个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

This answer is just for the said question. 这个答案仅适用于上述问题。 Since it manipulates the same array, it edits the receiver. 由于它操纵相同的数组,因此它编辑接收器。 For a more detailed and complete solution, check out Cary Swoveland's answer. 有关更详细和完整的解决方案,请查看Cary Swoveland的答案。

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

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