Track
/
Julia
Julia
/
Esercizi
/
Suggerimenti della boutique
Suggerimenti della boutique

Suggerimenti della boutique

Esercizio di apprendimento

Introduzione

Chiunque abbia usato Python ha quasi certamente usato le comprensioni di liste, che sono centrali nella sintassi di Python fin dalle prime versioni.

Qualcosa di così comodo si fa gradualmente strada anche in altri linguaggi, Julia compreso.

Per chi programma in Julia, le comprensioni sono un'opzione e non una necessità: di solito ci sono delle alternative (broadcasting, funzioni di ordine superiore, ecc.).

Tuttavia, una comprensione offrirà spesso un modo semplice, leggibile ed efficiente per costruire un array. Usarle o meno è alla fine una questione di gusto personale, e di come vedi Python rispetto ai linguaggi funzionali.

La sintassi è per lo più una copia diretta di Python, ma con estensioni per array a più dimensioni.

Una sola variabile

Molto pythonico, inclusa la clausola if opzionale.

julia> [x^2 for x in 1:3]
3-element Vector{Int64}:
 1
 4
 9
julia> [x^2 for x in 1:3 if isodd(x^2)]
2-element Vector{Int64}:
 1
 9

La forma dell'output dipende dai dettagli della comprensione: nei casi semplici è di solito la stessa della collezione di input, ma una clausola if la appiattisce in un Vector.

julia> m
2×3 Matrix{Int64}:
 1  2  3
 4  5  6
julia> [x^2 for x in m]
2×3 Matrix{Int64}:
  1   4   9
 16  25  36
julia> [x^2 for x in m if isodd(x^2)] 
3-element Vector{Int64}:
  1
 25
  9

Più variabili, output di tipo Vector

Come in Python, possiamo avere più clausole for con variabili diverse, con collezioni di input uguali o diverse.

julia> [x * y for x in 1:3 for y in 4:6]
9-element Vector{Int64}:
  4
  5
  6
  8
 10
 12
 12
 15
 18
julia> [x * y for x in 1:3 for y in 4:6 if isodd(x * y)]
2-element Vector{Int64}:
  5
 15

Questo equivale a cicli annidati. L'output è monodimensionale, anche quando l'input è una matrice.

julia> m
2×3 Matrix{Int64}:
 1  2  3
 4  5  6
julia> [x*y for x in m for y in m]
36-element Vector{Int64}:
  1
  4
  2
  5
(truncated output...)

Più variabili, output multidimensionale

La sezione precedente ha descritto più clausole for separate solo da spazi.

In questa sezione c'è un solo for e le variabili sono separate da virgole.

julia> [(x, y) for x in 1:3, y in 4:6]
3×3 Matrix{Tuple{Int64, Int64}}:
 (1, 4)  (1, 5)  (1, 6)
 (2, 4)  (2, 5)  (2, 6)
 (3, 4)  (3, 5)  (3, 6)

Ogni variabile della comprensione crea una nuova dimensione nell'output, con una voce per ogni possibile combinazione delle variabili.

Nell'esempio qui sopra, x aumenta scendendo lungo le righe, y aumenta scorrendo le colonne. Sono possibili dimensioni superiori, con le solite avvertenze sulla leggibilità dell'output.

Espressioni generatore

Le sezioni precedenti si sono concentrate sull'output di tipo array, con la comprensione racchiusa tra parentesi quadre [ ... ].

Quando le parentesi quadre vengono sostituite da parentesi tonde ( ... ), succede qualcosa di diverso: otteniamo una generator expression, un iteratore valutato pigramente che può produrre il valore successivo su richiesta.

julia> g = ((x, y) for x in 1:3, y in 4:6)
Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}, var"#9#10"}(var"#9#10"(), Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}((1:3, 4:6)))
# Indexing fails with a generator, the entries don't exist yet
julia> g[1, 2]
ERROR: MethodError: no method matching getindex(::Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{…}, UnitRange{…}}}, var"#9#10"}, ::Int64, ::Int64)
# conversion to array
julia> collect(g)
3×3 Matrix{Tuple{Int64, Int64}}:
 (1, 4)  (1, 5)  (1, 6)
 (2, 4)  (2, 5)  (2, 6)
 (3, 4)  (3, 5)  (3, 6)
# generators are mainly designed for iteration
julia> [i * j for (i, j) in g]
3×3 Matrix{Int64}:
  4   5   6
  8  10  12
 12  15  18

Quando il risultato di una comprensione viene usato subito per ulteriori elaborazioni, un generatore può essere efficiente in termini di memoria, evitando di dover memorizzare un grande array intermedio.

Un generatore usato come argomento di una funzione non ha bisogno di parentesi aggiuntive.

# inefficient
julia> v = [x^2 for x in 1:1e6];
julia> sum(v)
3.333338333335e17
# better - use a generator
julia> sum(x^2 for x in 1:1e6)
3.3333383333312755e17

La sintassi dei generatori è identica a quella delle comprensioni, a parte le parentesi che li racchiudono.

I generatori possono essere comodi anche nei costruttori di dizionari.

julia> Dict(x => x^2 for x in 1:5)
Dict{Int64, Int64} with 5 entries:
  5 => 25
  4 => 16
  2 => 4
  3 => 9
  1 => 1

Istruzioni

Lavori in una boutique di moda online. Ti viene l'idea di una funzionalità del sito dove vengono suggeriti degli abbinamenti all'utente. Ci interessano gli abbinamenti potenziali, i loro prezzi e l'eliminazione delle opzioni che stonano.

Note

Anche se ci possono essere modi diversi per risolvere i problemi seguenti, tutti si possono risolvere con una comprensione.

1. Crea un capo di abbigliamento

Implementa clothingitem() in modo che prenda due Tuple, uno di categories e l'altro delle rispettive qualities. La funzione deve restituire un Dict con le categories come chiavi e le qualities come valori.

julia> categories = ("item_name", "price", "color", "base_color");

julia> qualities = ("Descriptive Name", 99.00, "Ochre Red", "red");

julia> clothingitem(categories, qualities)
Dict{String, Any} with 4 entries:
  "price"      => 99.0
  "item_name"  => "Descriptive Name"
  "base_color" => "red"
  "color"      => "Ochre Red"

La funzione deve essere in grado di gestire qualsiasi numero di categories.

2. Suggerisci le combinazioni

Implementa get_combinations() in modo che prenda una Tuple di capi superiori e una Tuple di capi inferiori. La funzione deve restituire il cartesian product delle tuple come array bidimensionale (cioè una Matrix). Ogni voce è una combinazione (top, bottom) sotto forma di Tuple. I capi superiori cambiano scendendo lungo le righe, quelli inferiori lungo le colonne.

julia> tops = (
        Dict("item_name" => "Dress shirt"),
        Dict("item_name" => "Casual shirt")
        );

julia> bottoms = (
        Dict("item_name" => "Jeans"),
        Dict("item_name" => "Dress trousers")
       );

julia> get_combinations(tops, bottoms)
2×2 Matrix{Tuple{Dict{String, String}, Dict{String, String}}}:
 (Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Jeans"))   (Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Dress trousers"))
 (Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Jeans"))  (Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Dress trousers"))

3. Somma i prezzi degli abbinamenti

Ogni capo di abbigliamento ha un campo price associato, quindi può essere utile poter confrontare il prezzo totale di un abbinamento. Implementa get_prices(), che prende un array di combinazioni di capi. La funzione deve restituire un array della stessa forma, con i prezzi degli abbinamenti nelle rispettive posizioni.

julia> tops = (
        Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
        Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
       );

julia> bottoms = (
        Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
        Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
       );

julia> combomatrix = get_combinations(tops, bottoms);

julia> get_prices(combomatrix)
2×2 Matrix{Int}::
 65  110
 50   95

julia> filteredmatrix = filter_clashing(combomatrix)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
 (Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))

julia> get_prices(filteredmatrix)
1-element Vector{Int}:
 50

4. Filtra gli abbinamenti che stonano

Ogni capo di abbigliamento ha un campo base_color. Usa questo campo per rimuovere tutte le combinazioni in cui il capo superiore e quello inferiore hanno lo stesso colore di base. Implementa filter_clashing() in modo che prenda un array di combinazioni di capi. Restituisci un array monodimensionale (cioè un Vector) delle combinazioni corrispondenti.

julia> tops = (
        Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
        Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
       );

julia> bottoms = (
        Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
        Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
       );

julia> combos = get_combinations(tops, bottoms);

julia> filter_clashing(combos)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
 (Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))
Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
Julia Exercism

Vuoi iniziare Suggerimenti della boutique?

Iscriviti a Exercism per imparare e padroneggiare Julia con 35 concetti128 esercizi e il mentoring di persone reali, tutto gratis.