Scala: jaki jest najlepszy sposób na dołączenie elementu do tablicy?

111

Powiedz, że Array[Int]lubię

val array = Array( 1, 2, 3 )

Teraz chciałbym dołączyć element do tablicy, powiedzmy wartość 4, jak w poniższym przykładzie:

val array2 = array + 4     // will not compile

Mogę oczywiście używać System.arraycopy()i robić to samodzielnie, ale musi być do tego funkcja biblioteki Scala, której po prostu nie mogłem znaleźć. Dzięki za wskazówki!

Uwagi:

  1. Zdaję sobie sprawę, że mogę dołączyć kolejną tablicę elementów, jak w poniższym wierszu, ale wydaje się to zbyt okrągłe:

    val array2b = array ++ Array( 4 )     // this works
  2. Zdaję sobie sprawę z zalet i wad List vs Array i tutaj jestem z różnych powodów szczególnie zainteresowany rozszerzeniem Array.

Edytuj 1

Dzięki za odpowiedzi wskazujące na :+metodę operatorską. To jest to, czego szukałem. Niestety jest to raczej wolniejsze niż implementacja niestandardowej metody append () arraycopy- około dwa do trzech razy wolniejsza. Patrząc na implementację w programie SeqLike[], tworzony jest konstruktor, następnie tablica jest do niej dodawana, a następnie dodawane jest za pośrednictwem konstruktora, a następnie renderowany jest konstruktor. Niezbyt dobra implementacja dla tablic. Zrobiłem szybki test porównawczy, porównując dwie metody, patrząc na najszybszy czas z dziesięciu cykli. Wykonanie 10 milionów powtórzeń pojedynczego elementu dołączanego do 8-elementowej instancji tablicy pewnej klasy Foozajmuje 3,1 sekundy :+zi 1,7 sekundy przy użyciu prostej append()metodySystem.arraycopy();wykonanie 10 milionów powtórzeń dopisywania pojedynczych pozycji na 8-elementowych tablicach Long zajmuje 2,1 sekundy z :+prostą append()metodą i 0,78 sekundy . Zastanawiasz się, czy nie można tego naprawić w bibliotece za pomocą niestandardowej implementacji Array?

Edytuj 2

Za to, co jest warte, złożyłem bilet: https://issues.scala-lang.org/browse/SI-5017

Gregor Scheidt
źródło
11
Dlaczego nie użyć ArrayBufferi jego +=metody? To da ci zamortyzowany O (1) dodatek.
Fred Foo
1
W scali System.arraycopy(...)zostaje zastąpiony przezArray.copy(...)
paradygmatyczny
1
Czy zdajesz sobie sprawę z zalet i wad funkcji List vs Array, ale jesteś zaskoczony wynikami testów porównawczych 10 milionów dołączeń?
użytkownik nieznany
Czy możesz ponownie uruchomić test porównawczy, używając elementu, ArrayBufferktóry jest konwertowany po ostatnim dołączeniu do tablicy (z toArray)?
paradygmatyczny
@paradigmatic: Wzorem oczywiście nie było 10 milionów dodań do tej samej tablicy, ale 10 milionów powtórzeń dołączenia pojedynczego elementu do 8-elementowej tablicy. Odpowiednio zaktualizowałem pytanie.
Gregor Scheidt

Odpowiedzi:

204

Możesz użyć, :+aby dołączyć element do tablicy i +:poprzedzić go:

0 +: array :+ 4

powinien produkować:

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

Działa tak samo, jak w przypadku każdej innej implementacji Seq.

tenshi
źródło
3
Tak samo jest z każdą inną uporządkowaną kolekcją scala , nie działa na przykład z zestawem (ponieważ dołączanie i dołączanie nie ma znaczenia dla zestawu).
Nicolas,
@Nicolas Dowolna sekwencja. Uporządkowane implikacje posortowane .
Daniel C. Sobral,
@Daniel Tak, po napisaniu komentarza mam małą dziurkę w pamięci i nie znalazłem oczywistego słowa „sekwencja”
Nicolas
@tenshi czy wszystkie te operatory utworzyłyby nową tablicę? Tak, działa (od: + kod)Array.copy(repr, 0, result, 0, repr.length)
Timofey
60
val array2 = array :+ 4
//Array(1, 2, 3, 4)

Działa również „odwrócony”:

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

Dostępna jest również wersja „lokalna”:

var array = Array( 1, 2, 3 )
array +:= 4
//Array(4, 1, 2, 3)
array :+= 0
//Array(4, 1, 2, 3, 0)
Landei
źródło
11
Zastanawiam się tylko, dlaczego kolekcja Array nie używa metody append (), tak jak ArrayBuffer. Moim zdaniem to bardziej Koordynacja i ujednolicenie niż użycie nowego operatora: + / +:
Djvu
8

Najłatwiej byłoby:

Array(1, 2, 3) :+ 4

W rzeczywistości Array można implcitly przekształcić w plik WrappedArray

Nicolas
źródło
W takim przypadku byłaby to konwersja o wyższym priorytecie do ArrayOps
Didier Dupont