将scala中的for循环(循环变量)增加5的幂 [英] Incrementing the for loop (loop variable) in scala by power of 5

查看:324
本文介绍了将scala中的for循环(循环变量)增加5的幂的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Javaranch ,但无法在此处得到回应.因此也将其发布在这里:

I had asked this question on Javaranch, but couldn't get a response there. So posting it here as well:

我有一个特殊的要求,其中循环变量的增量是在每次迭代后将其乘以5来完成的.在Java中,我们可以这样实现:

I have this particular requirement where the increment in the loop variable is to be done by multiplying it with 5 after each iteration. In Java we could implement it this way:

for(int i=1;i<100;i=i*5){}

在scala中,我正在尝试以下代码-

In scala I was trying the following code-

var j=1
for(i<-1.to(100).by(scala.math.pow(5,j).toInt))
{
  println(i+" "+j)
  j=j+1
}

但是它打印以下输出: 1 1 6 2 11 3 16 4 21 5 26 6 31 7 36 8 .... ....

But its printing the following output: 1 1 6 2 11 3 16 4 21 5 26 6 31 7 36 8 .... ....

它总是以5递增.因此,我如何实际将增量乘以5而不是将其相加.

Its incrementing by 5 always. So how do I got about actually multiplying the increment by 5 instead of adding it.

推荐答案

首先让我们解释一下该问题.这段代码:

Let's first explain the problem. This code:

var j=1
for(i<-1.to(100).by(scala.math.pow(5,j).toInt))
{
  println(i+" "+j)
  j=j+1
}

等效于此:

var j = 1
val range: Range = Predef.intWrapper(1).to(100)
val increment: Int = scala.math.pow(5, j).toInt
val byRange: Range = range.by(increment)
byRange.foreach {
  println(i+" "+j)
  j=j+1
}

因此,当您突变j时,已经计算出incrementbyRange.而且Range是一个不可变对象-您无法更改它.即使在执行foreach时产生了新的范围,执行foreach的对象仍然相同.

So, by the time you get to mutate j, increment and byRange have already been computed. And Range is an immutable object -- you can't change it. Even if you produced new ranges while you did the foreach, the object doing the foreach would still be the same.

现在,解决问题了.简而言之,Range不足以满足您的需求.您需要一种几何级数,而不是算术级数.对我来说(似乎几乎所有其他人都在回答),自然的解决方案是使用由iterate创建的StreamIterator,它们根据前一个值计算下一个值.

Now, to the solution. Simply put, Range is not adequate for your needs. You want a geometric progression, not an arithmetic one. To me (and pretty much everyone else answering, it seems), the natural solution would be to use a Stream or Iterator created with iterate, which computes the next value based on the previous one.

for(i <- Iterator.iterate(1)(_ * 5) takeWhile (_ < 100)) {
  println(i)
}

关于流vs迭代器

StreamIterator是非常不同的数据结构,它们具有 non-strict 的属性.此属性使iterate甚至存在,因为此方法创建了一个无限集合 1 takeWhile将从中创建一个 new 2 集合是有限的.让我们在这里看看:

Stream and Iterator are very different data structures, that share the property of being non-strict. This property is what enables iterate to even exist, since this method is creating an infinite collection1, from which takeWhile will create a new2 collection which is finite. Let's see here:

val s1 = Stream.iterate(1)(_ * 5) // s1 is infinite
val s2 = s1.takeWhile(_ < 100)    // s2 is finite
val i1 = Iterator.iterate(1)(_ * 5) // i1 is infinite
val i2 = i1.takeWhile(_ < 100)      // i2 is finite

这些无限集合是可能的,因为该集合不是预先计算的.在List上,列表创建时,列表中的所有元素实际上都存储在某个位置.但是,在上述示例中,每个集合的第一个元素都是事先已知的.只有在需要时,才会计算所有其他值.

These infinite collections are possible because the collection is not pre-computed. On a List, all elements inside the list are actually stored somewhere by the time the list has been created. On the above examples, however, only the first element of each collection is known in advance. All others will only be computed if and when required.

但是,正如我提到的,这些在其他方面是非常不同的集合. Streamimmutable数据结构.例如,您可以根据需要多次打印s2的内容,并且每次都会显示相同的输出.另一方面,Iterator是可变数据结构.一旦使用了一个值,该值将永远消失.打印i2的内容两次,第二次将为空:

As I mentioned, though, these are very different collections in other respects. Stream is an immutable data structure. For instance, you can print the contents of s2 as many times as you wish, and it will show the same output every time. On the other hand, Iterator is a mutable data structure. Once you used a value, that value will be forever gone. Print the contents of i2 twice, and it will be empty the second time around:

scala> s2 foreach println
1
5
25

scala> s2 foreach println
1
5
25

scala> i2 foreach println
1
5
25

scala> i2 foreach println

scala> 

另一方面,

Streamlazy集合.一旦计算出一个值,它将 stay 进行计算,而不是每次都被丢弃或重新计算.参见下面有关该行为的一个示例:

Stream, on the other hand, is a lazy collection. Once a value has been computed, it will stay computed, instead of being discarded or recomputed every time. See below one example of that behavior in action:

scala>     val s2 = s1.takeWhile(_ < 100)    // s2 is finite
s2: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> println(s2)
Stream(1, ?)

scala> s2 foreach println
1
5
25

scala> println(s2)
Stream(1, 5, 25)

因此,Stream实际上可以在不注意的情况下填满内存,而Iterator则占用恒定的空间.另一方面,由于Iterator的副作用,可能会让您感到惊讶.

So Stream can actually fill up the memory if one is not careful, whereas Iterator occupies constant space. On the other hand, one can be surprised by Iterator, because of its side effects.

(1)实际上,Iterator根本不是一个集合,即使它共享许多由集合提供的方法.另一方面,从您给出的问题描述中,您并不想真正拥有一个数字集合,而只是对它们进行迭代.

(1) As a matter of fact, Iterator is not a collection at all, even though it shares a lot of the methods provided by collections. On the other hand, from the problem description you gave, you are not really interested in having a collection of numbers, just in iterating through them.

(2)实际上,尽管takeWhile将在Scala 2.8.0上创建一个新的Iterator,但是此新的迭代器仍将链接到旧的迭代器,并且其中的更改会对另一个产生副作用.这是有待讨论的,它们将来可能最终真正独立.

(2) Actually, though takeWhile will create a new Iterator on Scala 2.8.0, this new iterator will still be linked to the old one, and changes in one have side effects on the other. This is subject to discussion, and they might end up being truly independent in the future.

这篇关于将scala中的for循环(循环变量)增加5的幂的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆