Στην έννοια Vectors, είπαμε ότι "οι πίνακες βρίσκονται στην καρδιά της γλώσσας Julia" και ότι ένα διάνυσμα είναι μονοδιάστατο.
Δεδομένου αυτού, θα μπορούσαμε εύλογα να ελπίζουμε ότι η γλώσσα παρέχει πολλούς ευέλικτους και ισχυρούς τρόπους για να κάνουμε πράγματα με διανύσματα, ό,τι κι αν σημαίνει αυτό.
Κάποιες πολύ απλές συναρτήσεις δέχονται ένα διάνυσμα ως είσοδο και επιστρέφουν μια βαθμωτή τιμή ως έξοδο.
v = [2, 3, 4]
length(v) # => 3
sum(v) # => 9
Ας υποθέσουμε ότι έχεις ένα αριθμητικό διάνυσμα και θέλεις να αφαιρέσεις το 0.5 από κάθε τιμή.
julia> v = [1.2, 1.5, 1.7]
3-element Vector{Float64}:
1.2
1.5
1.7
julia> v - 0.5
ERROR: MethodError: no method matching -(::Vector{Float64}, ::Float64)
Αυτό αποτυγχάνει, οπότε τι γίνεται αν αφαιρέσουμε ένα άλλο διάνυσμα;
julia> v - [0.5, 0.5, 0.5]
3-element Vector{Float64}:
0.7
1.0
1.2
Πετυχημένο, αλλά αρκετά κουραστικό και απαιτητικό σε μνήμη όσο τα διανύσματα μεγαλώνουν.
Ευτυχώς, η Julia έχει μια "μαγική" τελεία για να λύσει αυτό το πρόβλημα πολύ απλά: το v .- 0.5 είναι το μόνο που χρειάζεσαι.
Η επόμενη ενότητα εξηγεί το γιατί.
Λοιπόν, το v - 0.5 αποτυγχάνει, αλλά το v .- 0.5 πετυχαίνει, και πρέπει να καταλάβουμε τι κάνει η τελεία.
Δύο πράγματα, που συνδυάζονται για να δώσουν το επιθυμητό αποτέλεσμα.
Πρώτα, η προσθήκη μιας τελείας πριν από έναν ενθηματικό τελεστή σημαίνει "εφάρμοσε αυτή την πράξη σε κάθε στοιχείο ξεχωριστά".
Παρομοίως, η προσθήκη μιας τελείας μετά το όνομα μιας συνάρτησης τη "διανυσματοποιεί", ακόμη κι αν η συνάρτηση έχει γραφτεί για βαθμωτές εισόδους.
julia> sqrt.([1, 4, 9])
3-element Vector{Float64}:
1.0
2.0
3.0
Είδαμε σε ένα προηγούμενο παράδειγμα ότι μπορούμε να αφαιρέσουμε διανύσματα ίσου μήκους, αν και καλό είναι να καταλάβεις ότι το .- είναι ασφαλέστερος τελεστής από το -, καθώς κάνει ξεκάθαρη την πρόθεση να δουλέψουμε στοιχείο προς στοιχείο.
julia> v .- [0.5, 0.5, 0.5]
3-element Vector{Float64}:
0.7
1.0
1.2
Τι γίνεται όμως με διανύσματα άνισου μήκους;
julia> v .- [0.5, 0.5]
ERROR: DimensionMismatch: arrays could not be broadcast to a common size
julia> v .- [0.5,]
3-element Vector{Float64}:
0.7
1.0
1.2
Γενικά, τα άνισα μήκη αποτελούν σφάλμα, εκτός όταν το ένα έχει μήκος 1 (τεχνικά, διάσταση μονοσυνόλου).
Τα μονοσύνολα όπως το [0.5,] ή απλώς το 0.5 επεκτείνονται αυτόματα στο απαραίτητο μήκος με επανάληψη.
Αυτό βρίσκεται στην καρδιά του broadcasting.
Η επιλογή στοιχείων ενός διανύσματος με τη θέση τους έχει συζητηθεί σε προηγούμενες έννοιες.
a = collect('A':'Z') # => 26-element Vector{Char}
# index with an integer
a[2] # => 'B'
# index with a range
a[12:2:18] # => ['L', 'N', 'P, 'R']
# index with another vector
a[ [1, 3, 5] ] # => ['A', 'C', 'E']
Είναι επίσης δυνατό να επιλέξεις στοιχεία που ικανοποιούν κάποια λογική έκφραση (τεχνικά, ένα "κατηγόρημα"). Αυτό συνήθως απαιτεί μετάδοση.
julia> a[a .< 'D']
3-element Vector{Char}:
'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)
'C': ASCII/Unicode U+0043 (category Lu: Letter, uppercase)
Σε πιο σύνθετες εκφράσεις οι τελείες τείνουν να πολλαπλασιάζονται (αλλά είναι μικρές και εύκολες στην πληκτρολόγηση).
julia> a[a .< 'D' .|| a .> 'W']
6-element Vector{Char}:
'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)
'C': ASCII/Unicode U+0043 (category Lu: Letter, uppercase)
'X': ASCII/Unicode U+0058 (category Lu: Letter, uppercase)
'Y': ASCII/Unicode U+0059 (category Lu: Letter, uppercase)
'Z': ASCII/Unicode U+005A (category Lu: Letter, uppercase)
Μια υπενθύμιση ότι το "διάνυσμα" μπορεί στην πραγματικότητα να είναι οποιοδήποτε κατάλληλο διατεταγμένο iterable, όπως ένα διάστημα:
julia> n = 3:10
3:10
julia> n[isodd.(n)]
4-element Vector{Int64}:
3
5
7
9
Είσαι ένας φανατικός παρατηρητής πουλιών που καταγράφει πόσα πουλιά επισκέφτηκαν τον κήπο σου τις τελευταίες επτά μέρες.
Έχεις έξι εργασίες, όλες σχετικές με τον αριθμό των πουλιών που επισκέφτηκαν τον κήπο σου.
Υλοποίησε τη συνάρτηση today() ώστε να επιστρέφει πόσα πουλιά επισκέφτηκαν τον κήπο σου σήμερα.
Οι αριθμοί των πουλιών είναι ταξινομημένοι ανά μέρα, με το πρώτο στοιχείο να είναι ο αριθμός της παλαιότερης μέρας και το τελευταίο στοιχείο τον σημερινό αριθμό.
julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> today(birds_per_day)
1
Υλοποίησε τη συνάρτηση increment_todays_count() ώστε να αυξάνει τον σημερινό αριθμό:
julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> increment_todays_count(birds_per_day)
[2, 5, 0, 7, 4, 2]
Υλοποίησε τη συνάρτηση has_day_without_birds() που επιστρέφει true αν υπήρξε μέρα κατά την οποία μηδέν πουλιά επισκέφτηκαν τον κήπο· αλλιώς, επέστρεψε false:
julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> has_day_without_birds(birds_per_day)
true
Υλοποίησε τη συνάρτηση count_for_first_days() που επιστρέφει τον αριθμό των πουλιών που επισκέφτηκαν τον κήπο σου από την αρχή της εβδομάδας, αλλά περιορίζει τον αριθμό στις συγκεκριμένες μέρες από την αρχή της εβδομάδας.
julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> count_for_first_days(birds_per_day, 4)
14
Κάποιες μέρες είναι πιο πολυάσχολες από άλλες.
Πολυάσχολη μέρα είναι εκείνη κατά την οποία πέντε ή περισσότερα πουλιά επισκέφτηκαν τον κήπο σου.
Υλοποίησε τη συνάρτηση busy_days() ώστε να επιστρέφει τον αριθμό των πολυάσχολων ημερών:
julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> busy_days(birds_per_day)
2
Αποφασίζεις να επεκτείνεις τις καταγραφές σου κρατώντας αριθμούς για πολλές εβδομάδες. Σε κάθε περίπτωση, οι αριθμοί είναι ταξινομημένοι ανά ημέρα της εβδομάδας, από τη Δευτέρα ως πρώτη καταχώριση έως την Κυριακή ως τελευταία.
Υλοποίησε τη συνάρτηση average_per_day() που επιστρέφει τον μέσο όρο για 2 εβδομάδες.
julia> week1 = [7, 2, 9, 1, 3, 0, 10]
julia> week2 = [2, 6, 4, 1, 3, 8, 9]
julia> average_per_day(week1, week2)
[4.5, 4.0, 6.5, 1.0, 4.0, 3.0, 9.5]
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Julia με 35 έννοιες128 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.