Scala: как лучше всего добавить элемент в массив?

111

Скажи, что мне Array[Int]нравится

val array = Array( 1, 2, 3 )

Теперь я хотел бы добавить в массив элемент, скажем значение 4, как в следующем примере:

val array2 = array + 4     // will not compile

Я, конечно, могу использовать System.arraycopy()и делать это сам, но для этого должна быть функция библиотеки Scala, которую я просто не мог найти. Спасибо за любые указатели!

Ноты:

  1. Я знаю, что могу добавить еще один массив элементов, как в следующей строке, но это кажется слишком круглым:

    val array2b = array ++ Array( 4 )     // this works
  2. Я знаю о преимуществах и недостатках List vs Array, и здесь меня по разным причинам особенно интересует расширение Array.

Редактировать 1

Спасибо за ответы, указывающие на :+метод оператора. Это то, что я искал. К сожалению, это намного медленнее, чем использование специальной реализации метода append () arraycopy- примерно в два-три раза медленнее. Глядя на реализацию в SeqLike[], создается построитель, затем к нему добавляется массив, затем выполняется добавление через построитель, затем построитель визуализируется. Плохая реализация для массивов. Я провел быстрый тест, сравнивая два метода, глядя на самое быстрое время из десяти циклов. Выполнение 10 миллионов повторений добавления одного элемента к экземпляру массива из 8 элементов некоторого класса Fooзанимает 3,1 секунды :+и 1,7 секунды с помощью простого append()метода, который используетSystem.arraycopy();выполнение 10 миллионов повторений добавления одного элемента на 8-элементные массивы Long занимает 2,1 секунды :+и 0,78 секунды при использовании простого append()метода. Интересно, нельзя ли это исправить в библиотеке с помощью специальной реализации для Array?

Редактировать 2

Чего стоит, билет я подал: https://issues.scala-lang.org/browse/SI-5017

Грегор Шайдт
источник
11
Почему бы не использовать ArrayBufferи его +=метод? Это даст вам амортизированное добавление O (1).
Фред Фу
1
В scala System.arraycopy(...)заменено наArray.copy(...)
paradigmatic
1
Вы знаете о преимуществах и недостатках List vs Array, но удивлены результатами тестов 10 миллионов добавлений?
user unknown
Можете ли вы снова запустить свой тест, используя, ArrayBufferкоторый преобразуется после последнего добавления в массив (с toArray)?
парадигматический
@paradigmatic: Конечно, тестом было не 10 миллионов добавлений к одному и тому же массиву, а 10 миллионов повторений добавления одного элемента к массиву из 8 элементов. Я обновил вопрос соответственно.
Грегор Шайдт,

Ответы:

205

Вы можете использовать :+для добавления элемента в массив и +:для его добавления :

0 +: array :+ 4

должен производить:

res3: Array[Int] = Array(0, 1, 2, 3, 4)

То же, что и с любой другой реализацией Seq.

Tenshi
источник
3
Это то же самое для любой другой упорядоченной коллекции scala , она не работает, например, с set (поскольку prepend и append ничего не значат для Set).
Николас
@Nicolas Любая последовательность. Упорядоченный означает отсортированный .
Дэниел С. Собрал
@Daniel Да, у меня просто образовалась небольшая дыра в памяти, когда я написал комментарий, и я не нашел очевидного слова «последовательность»
Николас
@tenshi все ли эти операторы создают новый массив? Да, есть (от: + code)Array.copy(repr, 0, result, 0, repr.length)
Тимофей
60
val array2 = array :+ 4
//Array(1, 2, 3, 4)

Также работает "реверс":

val array2 = 4 +: array
Array(4, 1, 2, 3)

Также существует версия "на месте":

var array = Array( 1, 2, 3 )
array +:= 4
//Array(4, 1, 2, 3)
array :+= 0
//Array(4, 1, 2, 3, 0)
Landei
источник
11
Мне просто интересно, почему в коллекции Array не используется метод append (), как и в ArrayBuffer. На мой взгляд, это больше координации и унификации, чем использование нового оператора: + / +:
Djvu
8

Самым простым может быть:

Array(1, 2, 3) :+ 4

Собственно, Array можно неявно преобразовать в WrappedArray

никола
источник
В этом случае это будет преобразование с более высоким приоритетом в ArrayOps
Дидье Дюпон