Διαδρομές
/
Julia
Julia
/
Ασκήσεις
/
Προτάσεις μπουτίκ
Προτάσεις μπουτίκ

Προτάσεις μπουτίκ

Άσκηση εκμάθησης

Εισαγωγή

Όποιος έχει χρησιμοποιήσει Python έχει σχεδόν σίγουρα χρησιμοποιήσει list comprehensions, τα οποία αποτελούν κεντρικό στοιχείο της σύνταξης της Python από τις πρώτες κιόλας εκδόσεις.

Κάτι τόσο βολικό βρίσκει σταδιακά τον δρόμο του και σε άλλες γλώσσες, ανάμεσά τους και η Julia.

Τα comprehensions είναι επιλογή και όχι αναγκαιότητα για τους προγραμματιστές της Julia, αφού συνήθως υπάρχουν εναλλακτικές (broadcasting, συναρτήσεις ανώτερης τάξης κ.λπ.).

Ωστόσο, ένα comprehension συχνά προσφέρει έναν απλό, ευανάγνωστο και αποδοτικό τρόπο για να κατασκευάσεις έναν πίνακα. Η χρήση του είναι τελικά θέμα προσωπικού γούστου, και του πώς νιώθεις για την Python έναντι των συναρτησιακών γλωσσών.

Η σύνταξη είναι ως επί το πλείστον ένα άμεσο αντίγραφο της Python, αλλά με επεκτάσεις για πίνακες περισσότερων διαστάσεων.

Μία μεταβλητή

Πολύ pythonικό, μαζί με την προαιρετική ρήτρα if.

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

Το σχήμα της εξόδου εξαρτάται από τις λεπτομέρειες του comprehension: συνήθως είναι ίδιο με τη συλλογή εισόδου σε απλές περιπτώσεις, αλλά με μια ρήτρα if γίνεται ένα επίπεδο 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

Πολλαπλές μεταβλητές, έξοδος Vector

Όπως στην Python, μπορούμε να έχουμε πολλαπλές ρήτρες for με διαφορετικές μεταβλητές, με ίδιες ή διαφορετικές συλλογές εισόδου.

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

Αυτό ισοδυναμεί με εμφωλευμένους βρόχους. Η έξοδος είναι μονοδιάστατη, ακόμη και με πίνακα ως είσοδο.

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...)

Πολλαπλές μεταβλητές, πολυδιάστατη έξοδος

Η προηγούμενη ενότητα περιέγραψε πολλαπλές ρήτρες for που χωρίζονται μόνο με κενά.

Σε αυτή την ενότητα υπάρχει ένα μόνο for και οι μεταβλητές χωρίζονται με κόμμα.

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)

Κάθε μεταβλητή στο comprehension δημιουργεί μια νέα διάσταση στην έξοδο, με μία καταχώριση για κάθε πιθανό συνδυασμό των μεταβλητών.

Στο παραπάνω παράδειγμα, το x αυξάνεται προς τα κάτω στις γραμμές, το y αυξάνεται προς τα δεξιά στις στήλες. Υπάρχουν και μεγαλύτερες διαστάσεις, με τις συνήθεις προειδοποιήσεις για την ευαναγνωσιμότητα της εξόδου.

Εκφράσεις γεννήτριας

Οι προηγούμενες ενότητες επικεντρώθηκαν στην έξοδο πίνακα, με το comprehension μέσα σε αγκύλες [ ... ].

Όταν οι αγκύλες αντικαθίστανται από παρενθέσεις ( ... ), συμβαίνει κάτι διαφορετικό: παίρνουμε μια generator expression: έναν iterator με οκνηρή αξιολόγηση, που μπορεί να παράγει την επόμενη τιμή όταν του ζητηθεί.

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

Όταν το αποτέλεσμα ενός comprehension χρησιμοποιείται αμέσως για περαιτέρω επεξεργασία, μια γεννήτρια μπορεί να είναι αποδοτική ως προς τη μνήμη, αποφεύγοντας την ανάγκη να αποθηκευτεί ένας μεγάλος ενδιάμεσος πίνακας.

Μια γεννήτρια που χρησιμοποιείται ως όρισμα συνάρτησης δεν χρειάζεται επιπλέον παρενθέσεις.

# 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

Η σύνταξη της γεννήτριας είναι ίδια με των comprehensions, με μόνη διαφορά τις αγκύλες που την περιβάλλουν.

Οι γεννήτριες μπορούν επίσης να φανούν βολικές σε κατασκευαστές λεξικών.

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

Οδηγίες

Δουλεύεις σε ένα ηλεκτρονικό κατάστημα μόδας. Σου έρχεται η ιδέα για μια λειτουργία της ιστοσελίδας όπου προτείνονται σύνολα στον χρήστη. Αυτό που έχει ενδιαφέρον είναι τα πιθανά σύνολα, οι τιμές τους και η εξάλειψη των ασύμβατων επιλογών.

Note

Αν και μπορεί να υπάρχουν διαφορετικοί τρόποι να λύσεις τα παρακάτω προβλήματα, όλα μπορούν να λυθούν με μια comprehension.

1. Δημιούργησε ένα κομμάτι ρούχου

Υλοποίησε τη συνάρτηση clothingitem() ώστε να δέχεται δύο Tuple, το ένα με categories και το άλλο με τις αντίστοιχες qualities. Η συνάρτηση πρέπει να επιστρέφει ένα Dict με τα categories ως κλειδιά και τα qualities ως τιμές.

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"

Η συνάρτηση σου πρέπει να μπορεί να χειριστεί οποιονδήποτε αριθμό categories.

2. Πρότεινε συνδυασμούς

Υλοποίησε τη συνάρτηση get_combinations() ώστε να δέχεται ένα Tuple με πάνω ρούχα και ένα Tuple με κάτω ρούχα. Η συνάρτηση πρέπει να επιστρέφει το cartesian product των πλειάδων ως δισδιάστατο πίνακα (δηλ. Matrix). Κάθε στοιχείο είναι ένας συνδυασμός (top, bottom) με τη μορφή Tuple. Τα πάνω ρούχα αλλάζουν καθώς κατεβαίνεις τις γραμμές, τα κάτω ρούχα αλλάζουν καθώς προχωράς στις στήλες.

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. Άθροισε τις τιμές των συνόλων

Κάθε κομμάτι ρούχου έχει ένα πεδίο price που σχετίζεται με αυτό, οπότε θα ήταν χρήσιμο να μπορείς να συγκρίνεις τη συνολική τιμή των συνόλων. Υλοποίησε τη συνάρτηση get_prices(), η οποία δέχεται έναν πίνακα με συνδυασμούς ρούχων. Η συνάρτηση πρέπει να επιστρέφει έναν πίνακα με το ίδιο σχήμα, που να περιέχει τις τιμές των συνόλων στις αντίστοιχες θέσεις τους.

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. Φίλτραρε τα ασύμβατα σύνολα

Κάθε κομμάτι ρούχου έχει ένα πεδίο base_color. Χρησιμοποίησε αυτό το πεδίο για να αφαιρέσεις όλους τους συνδυασμούς όπου το πάνω και το κάτω ρούχο έχουν το ίδιο βασικό χρώμα. Υλοποίησε τη συνάρτηση filter_clashing() ώστε να δέχεται έναν πίνακα με συνδυασμούς ρούχων. Επίστρεψε έναν μονοδιάστατο πίνακα (δηλ. Vector) με τους συνδυασμούς που ταιριάζουν.

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"))
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα
Julia Exercism

Έτοιμος να ξεκινήσεις την άσκηση Προτάσεις μπουτίκ;

Γράψου στο Exercism για να μάθεις και να κατακτήσεις Julia με 35 έννοιες128 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.