Ve

Vettori in Julia

1 esercizio

Informazioni su Vettori

Uno degli obiettivi centrali di Julia è poter eseguire calcoli su dati numerici, in modo rapido ed efficiente. Tantissimi dati numerici.

Di solito i dati sono memorizzati in array (o in qualche tipo correlato), quindi è ragionevole dire che gli array sono al centro del linguaggio Julia.

Gli array possono avere dimensioni arbitrarie (soggette solo ai limiti di memoria dell'hardware) e possono avere un numero arbitrario di dimensioni.

Alcuni tipi di array hanno nomi speciali (presi in prestito dall'algebra lineare). Un array monodimensionale si chiama Vector e un array bidimensionale si chiama Matrix. Entrambi sono sottotipi di Array in Julia.

Questo concetto introduttivo si concentra sulle basi dei Vector. Gli array con più dimensioni saranno trattati più avanti nel percorso.

Creare i Vector

In Julia, un Vector è una sequenza ordinata di valori a cui si può accedere tramite un numero di indice.

Il modo più semplice per creare un Vector è elencare i valori tra parentesi quadre:

julia> num_vec = [1, 4, 9]
3-element Vector{Int64}:
 1
 4
 9

julia> str_vec = ["arrays", "are", "important"]
3-element Vector{String}:
 "arrays"
 "are"
 "important"

Il tipo del Vector corrisponde al tipo di ogni elemento.

Tecnicamente è un vettore colonna, ma per ora ignora questo dettaglio se non hai familiarità con l'algebra lineare. Dovrebbe avere più senso dopo il concetto sugli array multidimensionali.

Quindi i Vector devono essere omogenei (tutti gli elementi dello stesso tipo)?

A un certo livello, sì, ed è consigliabile puntare a questo se vuoi le prestazioni migliori. Tuttavia, Julia può aggirare questa limitazione (quando serve) usando il tipo Any:

julia> mixed_vector = [1, "str", 'c']
3-element Vector{Any}:
 1
  "str"
  'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)

Quando si crea un Vector vuoto, Julia usa per impostazione predefinita il tipo di elemento Any, ma è possibile definirlo in modo più specifico annotando l'array vuoto con il tipo di elemento desiderato.

julia> empty_vec = []
Any[]

julia> empty_int_vec = Int64[]
Int64[]

Vector pre-riempiti

È molto comune partire da vector con tutti i valori uguali a 0 o a 1. Per questi ci sono le funzioni (non sorprende) zeros() e ones(), che prendono come parametro la dimensione del vector. Il tipo predefinito è Float64, ma è possibile specificare facoltativamente altri tipi numerici.

Per estensione, la funzione fill() accetta sia un valore da ripetere sia la dimensione desiderata del vector.

julia> zeros(3)
3-element Vector{Float64}:
 0.0
 0.0
 0.0

julia> ones(3)
3-element Vector{Float64}:
 1.0
 1.0
 1.0

julia> ones(Int64, 3)
3-element Vector{Int64}:
 1
 1
 1

julia> fill(42, 3)
3-element Vector{Int64}:
 42
 42
 42

Ci sono molte altre opzioni: vedi il manuale.

Leggi e ricorda bene questa regola:

  • Per impostazione predefinita, l'indicizzazione in Julia parte da 1, non da 0.

È una cosa familiare a chiunque abbia usato altri linguaggi per la data science (R, Matlab, Fortran...), ma può sembrare sconvolgente a chi ha una formazione in linguaggi simili al C.

Per il resto, gli indici funzionano come potresti immaginare: basta metterli tra parentesi quadre:

squares = [0, 1, 4, 9, 16]
squares[1]  # 0
squares[3]  # 4
squares[begin]  # 0 ("begin" is synonym for 1)
squares[end]  # 16 ("end" is synonym for length(squares))

Nota la comodità di indicizzare con end (molto utile) e con begin (probabilmente no).

Chi programma in Python potrebbe chiedersi se esistono gli indici negativi. Non è così: non fanno parte di Julia e generano un BoundsError, come qualsiasi indice minore di 1 o maggiore di length(squares).

Operazioni sui Vector

I Vector in Julia sono mutabili: possiamo cambiare il contenuto delle singole celle.

julia> vals = [1, 3, 5, 7]
4-element Vector{Int64}:
 1
 3
 5
 7

julia> vals[2] = 4  # reassign the value of this element
4

# Only the value at position 2 changes:
julia> vals
4-element Vector{Int64}:
 1
 4
 5
 7

Ci sono molte funzioni disponibili per manipolare i vector, anche se la documentazione di Julia le generalizza a «collections» anziché a vector.

Nota che, per convenzione, le funzioni che modificano il loro input hanno un ! nel nome. Il compilatore non lo impone, ma nel mondo Julia è una convenzione molto forte.

Queste sono alcune delle funzioni più utili:

  • Per aggiungere valori alla fine del vector, usa push!().
  • Per rimuovere l'ultimo valore, usa pop!().
  • Per operare sull'inizio del vector, le funzioni corrispondenti sono pushfirst!() e popfirst!().
  • Per inserire o rimuovere un elemento in una posizione qualsiasi, ci sono insert!() e deleteat!().
julia> vals = [1, 3]
2-element Vector{Int64}:
 1
 3

julia> push!(vals, 5, 6)  # can add multiple values
4-element Vector{Int64}:
 1
 3
 5
 6

julia> pop!(vals)  # mutates vals, return popped value
6

julia> vals
3-element Vector{Int64}:
 1
 3
 5

Concatenazione

La concatenazione è abbastanza semplice per i vector, anche se una rapida occhiata al manuale lascia intravedere le complessità che ci aspettano quando si passa agli array multidimensionali.

La funzione append!() può accettare come input una combinazione di più vector e di singoli elementi.

julia> append!([1, 2], [3, 4], [-1, -2], 15)
7-element Vector{Int64}:
  1
  2
  3
  4
 -1
 -2
 15
Modifica tramite GitHub Il collegamento si apre in una nuova finestra o scheda

Impara Vettori