отображать диапазон непосредственно в массив

Следующий код создает временный вектор:

0.to(15).map(f).toArray
^^^^^^^^
Sequence
^^^^^^^^^^^^^^^
    temp Vector
^^^^^^^^^^^^^^^^^^^^^^^
                  Array

Следующий код создает временный массив:

0.to(15).toArray.map(f)
^^^^^^^^
Sequence
^^^^^^^^^^^^^^^
     temp Array
^^^^^^^^^^^^^^^^^^^^^^^
                  Array

Есть ли способ сопоставить f с последовательностью и напрямую получить массив, не создавая временный?


person fredoverflow    schedule 06.09.2017    source источник


Ответы (2)


Вы можете использовать breakOut:

val res: Array[Int] = 0.to(15).map(f)(scala.collection.breakOut)

or

0.to(15).map[Int, Array[Int]](f)(scala.collection.breakOut)

или используйте view:

0.to(15).view.map(f).to[Array]

Дополнительную информацию о представлениях см. в этом документе.

person Ziyang Liu    schedule 06.09.2017
comment
Не могли бы вы вкратце объяснить, что делает breakOut? - person fredoverflow; 06.09.2017
comment
Также кажется, что 0.to(15).map[Int, Array[Int]](f) уже работает без дополнительного списка параметров (scala.collection.breakOut). - person fredoverflow; 06.09.2017
comment
Короче говоря, breakOut — это метод, который находит правильный экземпляр CanBuildFrom на основе желаемого типа ввода и вывода, который в противном случае компилятор не сможет правильно вывести. С правильным экземпляром CanBuildFrom вы можете создать новый тип коллекции при сопоставлении с исходной коллекцией. Дополнительные сведения см. на странице stackoverflow.com/questions/1715681/scala-2-8-breakout. - person Ziyang Liu; 06.09.2017
comment
0.to(15).map[Int, Array[Int]](_ + 1) у меня не работает в Scala 2.12.3, так как компилятор жалуется, что не может найти CanBuildFrom. - person Ziyang Liu; 06.09.2017
comment
В моем случае f — это конкретная функция, поэтому компилятор уже знает ее тип. Это работает с (_ + 1: Int => Int) или чем-то подобным? - person fredoverflow; 06.09.2017
comment
Нет - 0.to(15).map[Int, Array[Int]]((_ + 1): Int => Int) не компилируется с той же ошибкой, что и 0.to(15).map[Int, Array[Int]](_ + 1), которая в основном говорит, что CanBuildFrom не может быть найден. - person Ziyang Liu; 06.09.2017
comment
Ты прав. Я только что проверил, и он не компилируется в 2.12.3 (но успешно компилируется в 2.11.11)... - person fredoverflow; 06.09.2017

Если вы знаете, как создать начальный Range, вы можете использовать Array.range(start, end) из Array сопутствующий объект, который создает Range напрямую как Array без приведения:

Array.range(0, 15) // Array[Int] = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)

который может быть преобразован из Array в Array как таковой:

Array.range(0, 15).map(f) // Array[Int] = Array(0, 2, 4, 6, 8, 10, 12, 14, ...)

Примечание. Array.range(i, j) эквивалентно i until j (i to j+1), а не i to j.


Еще короче и за один проход, но менее читабельно, используя Array.tabulate:

Array.tabulate(15)(f) // Array[Int] = Array(0, 2, 4, 6, 8, 10, 12, 14, ...)
person Xavier Guihot    schedule 24.07.2018