Заполнение списка - это Scala со случайным двойным взятием навсегда - PullRequest
5 голосов
/ 14 марта 2011

Я новичок в Scala и пытаюсь получить список случайных двойных значений:

Дело в том, что когда я пытаюсь запустить это, это занимает слишком много времени по сравнению с его Java-аналогом. Любые идеи о том, почему это или предложение о более эффективном подходе?

def random: Double = java.lang.Math.random()
var f = List(0.0)
for (i <- 1 to 200000)
 ( f = f ::: List(random*100)) 
 f = f.tail

Ответы [ 7 ]

21 голосов
/ 15 марта 2011

Вы также можете достичь этого следующим образом:

List.fill(200000)(math.random)

То же самое относится, например, к массиву ...

Array.fill(200000)(math.random)

и т. Д.

9 голосов
/ 14 марта 2011

Вы можете создать бесконечный поток случайных двойных чисел:

def randomList(): Stream[Double] = Stream.cons(math.random, randomList)

val f = randomList().take(200000)

Это будет использовать ленивую оценку, поэтому вы не будете вычислять значение, пока оно вам действительно не понадобится.Даже оценка всех 200 000 будет быстрой, хотя.В качестве дополнительного бонуса, f больше не должен быть var.

7 голосов
/ 15 марта 2011

Другая возможность:

val it = Iterator.continually(math.random)
it.take(200000).toList

Stream также имеет метод continually, если вы предпочитаете.

5 голосов
/ 15 марта 2011

Прежде всего, это не займет больше времени, чем Java, потому что нет аналога Java.У Java нет неизменного списка.Если бы это было так, производительность была бы примерно одинаковой.

Во-вторых, это отнимает много времени, потому что добавляющие списки имеют линейную производительность, поэтому все это имеет квадратичную производительность.препенд, который имел постоянную производительность.

4 голосов
/ 14 марта 2011

если вы в любом случае используете изменяемое состояние, вы должны использовать изменяемую коллекцию, такую ​​как буфер, которую вы также можете добавить с помощью += (который тогда будет действительным аналогом java-кода).

но почему ты не используешь понимание списка?

val f = for (_ <- 1 to 200000) yield (math.random * 100)

кстати: var f = List(0.0) ... f = f.tail можно заменить на var f: List[Double] = Nil в вашем примере. (не больше производительности, но больше красоты;)

2 голосов
/ 15 марта 2011

Еще больше вариантов!Хвостовая рекурсия:

def randlist(n: Int, part: List[Double] = Nil): List[Double] = {
  if (n<=0) part
  else randlist(n-1, 100*random :: part)
}

или сопоставленные диапазоны:

(1 to 200000).map(_ => 100*random).toList
1 голос
/ 15 марта 2011

Похоже, вы хотите использовать Vector вместо List.Список имеет O (1) добавление, Вектор имеет O (1) добавление.Поскольку вы добавляете, но используете конкатенацию, будет быстрее использовать Vector:

def random: Double = java.lang.Math.random()
var f: Vector[Double] = Vector()
for (i <- 1 to 200000)
  f = f :+ (random*100)

Понятно?

...