Διαδρομές
/
jq
jq
/
Ασκήσεις
/
Λίστα αγορών
Λίστα αγορών

Λίστα αγορών

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

Εισαγωγή

Τα βασικά

Θα υποθέσουμε ότι είσαι εξοικειωμένος με τη σύνταξη και τους τύπους δεδομένων της JSON.

Το jq λειτουργεί περνώντας τα δεδομένα JSON που έρχονται μέσα από μία μόνο έκφραση (γραμμένη ως σωλήνωση φίλτρων) για να πετύχεις τα επιθυμητά μετασχηματισμένα δεδομένα.

Note

Η γλώσσα jq υλοποιείται από το πρόγραμμα jq. Αυτό το πρόγραμμα παρέχει αρκετές βολικές επιλογές γραμμής εντολών που ελέγχουν πώς καταναλώνεται η είσοδος και πώς παρουσιάζεται η έξοδος.

Στα παρακάτω παραδείγματα θα συναντήσεις:

  • -n ή --null-input

    Κανονικά, στο πρόγραμμα jq δίνεται ένα αρχείο για ανάγνωση ή στέλνεις δεδομένα στην είσοδό του. Η επιλογή --null-input σου επιτρέπει να παράγεις δεδομένα JSON χωρίς καμία είσοδο.

  • -c ή --compact-output

    Το jq μορφοποιεί όμορφα την έξοδό του από προεπιλογή. Είναι εξαιρετικά χρήσιμο για τους ανθρώπους να βλέπουν τα δεδομένα όταν είναι ωραία μορφοποιημένα. Ωστόσο, αυτό δεν είναι απαραίτητο για τις μηχανές: η επιλογή --compact-output αφαιρεί τα κενά μορφοποίησης για να ελαχιστοποιήσει το μέγεθος του JSON που προκύπτει.

  • -f filename ή --from-file filename

    Διάβασε το πρόγραμμα jq από το filename αντί να το δώσεις στη γραμμή εντολών. Τόσο το sed όσο και το awk χρησιμοποιούν την επιλογή -f για τον ίδιο σκοπό. Θα το δεις να χρησιμοποιείται στα scripts δοκιμών για τις ασκήσεις εξάσκησης.

Το υπόλοιπο αυτής της ενότητας θα επικεντρωθεί στη γλώσσα jq.

Φίλτρα και σωλήνες

Τα φίλτρα είναι επίσης γνωστά ως εκφράσεις.

Ένα φίλτρο παίρνει μια είσοδο και παράγει μια έξοδο. Όπως ακριβώς δουλεύεις σε ένα κέλυφος unix, μπορείς να ενώσεις φίλτρα με έναν σωλήνα | για να συνδέσεις την έξοδο ενός φίλτρου με την είσοδο ενός άλλου.

Το φίλτρο ταυτότητας: .

Αυτό είναι το πιο απλό φίλτρο. Απλώς περνάει την είσοδό του στην έξοδό του.

$ echo '[1, 2, 3]' | jq '.'
[
  1,
  2,
  3
]

Πίνακες

Αυτή θα είναι μια γρήγορη εισαγωγή στην εργασία με πίνακες. Θα καλύψουμε αυτό το θέμα με περισσότερες λεπτομέρειες αργότερα.

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

$ echo '[10, 20, 30]' | jq '.[1]'
20

Ένα φίλτρο μπορεί να φτιάξει έναν πίνακα τυλίγοντας μια έκφραση μέσα σε [ και ]

  • με μια γνωστή λίστα στοιχείων:

    jq -n '[1, 2, 3]'
    
  • για να συλλέξει μια ροή στοιχείων: για παράδειγμα, το range είναι μια συνάρτηση που παράγει μια ροή αριθμών

    $ jq -n 'range(10; 70; 15)'
    10
    25
    40
    55
    

    Χρησιμοποιώντας το [] συλλέγεις τα αποτελέσματα της έκφρασης σε έναν πίνακα

    $ jq -c -n '[range(10; 70; 15)]'
    [10,25,40,55]
    

Το κόμμα είναι τελεστής

Το κόμμα δεν είναι απλώς σύνταξη που χωρίζει στοιχεία πίνακα. Το κόμμα είναι ένας τελεστής που ενώνει ροές.

Για παράδειγμα, το [1, 2, 3] είναι ένα φίλτρο που χρησιμοποιεί τον κατασκευαστή πίνακα [] για να συλλέξει το αποτέλεσμα της ένωσης των τριών εκφράσεων 1, 2 και 3.

Πρόσεξες τις άνω τελείες στο range(10; 70; 15) παραπάνω; Επειδή τα κόμματα έχουν συγκεκριμένο σκοπό στη γλώσσα jq, οι συναρτήσεις που παίρνουν πολλά ορίσματα χρησιμοποιούν άνω τελείες για να χωρίσουν τα ορίσματα.

Αντικείμενα

Μια γρήγορη εισαγωγή στα αντικείμενα.

Όπως σε πολλές γλώσσες προγραμματισμού, χρησιμοποίησε τελείες για να προσπελάσεις τις ιδιότητες ενός αντικειμένου

$ echo '{"foo": {"bar": "qux"}}' | jq '.foo.bar'
"qux"
Note

Οι αγκύλες μπορούν να χρησιμοποιηθούν και για αντικείμενα, αλλά τότε χρειάζονται εισαγωγικά για τις κυριολεκτικές συμβολοσειρές. Αυτός είναι ένας τρόπος να δουλέψεις με κλειδιά που περιέχουν κενά.

$ echo '{"foo bar": "qux"}' | jq '.["foo bar"]'
"qux"

Μπορείς να κατασκευάσεις ένα αντικείμενο με {} και ζεύγη key: value. Τα εισαγωγικά δεν απαιτούνται γύρω από κλειδιά που είναι "απλές" συμβολοσειρές.

jq -n '{question: (6 * 9), answer: 42}'

παράγει

{
  "question": 54,
  "answer": 42
}

Για να αντιμετωπίσεις το κλειδί ως έκφραση, πρέπει να το τυλίξεις σε παρενθέσεις (το παρακάτω επίσης παράγει το ίδιο αποτέλεσμα με πάνω).

echo '[{"key":"question", "value":54}, {"key":"answer", "value":42}]' \
| jq '{(.[0].key): .[0].value, (.[1].key): .[1].value}'

Σωληνώσεις

Για παράδειγμα, δίνεται το file.json που περιέχει

{
  "key1": "value1",
  "key2": [5, 15, 25]
}

Ας υπολογίσουμε το μήκος του πίνακα key2:

$ jq '.key2 | length' file.json
3

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

Τα φίλτρα μπορούν να αγνοήσουν την είσοδό τους

Σε αυτό το παράδειγμα, τα δεδομένα εισόδου JSON αγνοούνται και δεν επηρεάζουν την έξοδο:

$ echo '{"answer": 42}' | jq '6 * 9'
54

Τα φίλτρα μπορούν να παράγουν ροές δεδομένων

Ένα φίλτρο μπορεί να παράγει περισσότερες από μία τιμές. Για παράδειγμα, το φίλτρο .[] παράγει κάθε στοιχείο ενός πίνακα ως ξεχωριστή τιμή:

$ jq -n -c '[1, 2, 3]'
[1,2,3]

$ jq -n -c '[1, 2, 3] | .[]'
1
2
3

Η διοχέτευση ενός τέτοιου φίλτρου σε ένα άλλο θα εκτελέσει το δεύτερο φίλτρο για κάθε τιμή:

$ jq -n -c '[1, 2, 3] | .[] | . * 2'
2
4
6

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

Παρενθέσεις

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

Για παράδειγμα, ας υποθέσουμε ότι θέλουμε να κατασκευάσουμε έναν πίνακα με 2 στοιχεία: την τετραγωνική ρίζα του 9 και το e υψωμένο στη δύναμη 1. Οι δύο επιμέρους εκφράσεις είναι 9 | sqrt και 1 | exp. Περιμένουμε η έξοδος να είναι ο πίνακας [3, 2.7...]

$ jq -n '[ 9|sqrt, 1|exp ]'
[
  20.085536923187668,
  2.718281828459045
]

Γιατί δεν πήραμε αυτό που περιμέναμε; Το jq το ερμηνεύει ως εξής:

[ ((9|sqrt), 1) | exp ]

Το jq φτιάχνει μια ροή δύο στοιχείων (3 και 1), τα οποία δίνονται το καθένα στο exp.

Πρέπει να διασφαλίσουμε ότι το exp παίρνει μόνο έναν αριθμό ως είσοδο. Με άλλα λόγια, πρέπει να επιβάλουμε ο σωλήνας να αξιολογείται πριν από το κόμμα.

$ jq -n '[ 9|sqrt, (1|exp) ]'
[
  3,
  2.718281828459045
]

Συναρτήσεις και τελεστές

Χωρίς να μπούμε σε μεγάλο βάθος (οι συναρτήσεις θα είναι θέμα για άλλη άσκηση), ορίστε μερικές χρήσιμες ενσωματωμένες συναρτήσεις:

  • length

    Με έναν πίνακα ως είσοδο, παράγει τον αριθμό των στοιχείων του πίνακα.

    $ jq -n '[10, 20, 30, 40] | length'
    4
    
  • +

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

    $ jq -c -n '
        3 + 4,
        "foo" + "bar",
        ["a", "b"] + ["c"],
        {"m": 10} + {"n": 20}
    '
    7
    "foobar"
    ["a","b","c"]
    {"m":10,"n":20}
    

    Το add είναι μια συνάρτηση που παίρνει έναν πίνακα και επιστρέφει ένα στοιχείο με όλα τα στοιχεία αθροισμένα σύμφωνα με τους κανόνες του +. Το [1, 2, 3] | add παράγει 6.

  • map

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

    $ jq -c -n '[10, 20, 30, 40] | map(. / 5)'
    [2,4,6,8]
    
  • select

    Με κάποια είσοδο και ένα φίλτρο ως όρισμα:

    • αν το φίλτρο που εφαρμόζεται στο όρισμα οδηγεί σε αληθή τιμή, παράγει την είσοδο αμετάβλητη
    • διαφορετικά, δεν παράγει τίποτα (όχι την τιμή null, πραγματικά καμία έξοδο)

    Για παράδειγμα, δίνονται κάποιοι αριθμοί, διάλεξε αυτούς που διαιρούνται με το 3

    $ jq -n 'range(10) | select(. % 3 == 0)'
    0
    3
    6
    9
    

    Θυμήσου ότι το range παράγει μια ροή αριθμών. Το select θα καλείται μία φορά για κάθε αριθμό. Παράγονται μόνο οι αριθμοί που "περνούν" την έκφραση.

    Συχνά χρειάζεται να διαλέξεις στοιχεία ενός πίνακα. Υπάρχουν μερικοί τρόποι να το κάνεις αυτό.

    Με είσοδο ["Anne", "Bob", "Cathy", "Dave"], διάλεξε τα ονόματα που έχουν μήκος 4.

    • χρησιμοποίησε το map και το select μαζί

      map(select(length == 4))
      
    • σπάσε τον πίνακα στα στοιχεία του, εφάρμοσε select σε αυτή τη ροή και μάζεψε τα αποτελέσματα

      [ .[] | select(length == 4) ]
      

Σχόλια

Τα σχόλια ξεκινούν με τον χαρακτήρα # και συνεχίζουν μέχρι το τέλος της γραμμής.

Οδηγίες

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

{
  "name": "name of shopping list",
  "ingredients": [ ...list of ingredients... ],
  "optional ingredients": [ ...list of ingredients... ]
}

Ένα υλικό αναπαρίσταται ως αντικείμενο JSON, όπως:

{
  "item": "flour",
  "amount": {
    "quantity": 2,
    "unit": "cup"
  }
}

Ένα υλικό έχει μια προαιρετική ιδιότητα με όνομα "substitute" που περιέχει μια συμβολοσειρά με ένα άλλο υλικό που μπορεί να χρησιμοποιηθεί στη θέση του.

Ας δούμε πώς μπορούμε να εξετάσουμε τη λίστα αγορών με το jq

1. Εξήγαγε το όνομα της λίστας αγορών

Γράψε μια έκφραση που να βγάζει το στοιχείο "name" της λίστας αγορών.

2. Μέτρησε πόσα υλικά χρειάζονται

Μέτρησε μόνο τα υποχρεωτικά υλικά. Μη συμπεριλάβεις τα προαιρετικά υλικά.

3. Πόση ζάχαρη;

Γράψε μια έκφραση που να βγάζει την ποσότητα ζάχαρης. Θέλουμε μόνο το αριθμητικό μέρος.

4. Αντιστοίχισε τα υλικά που μπορούν να αντικατασταθούν

Μερικά από τα υλικά μπορούν να αντικατασταθούν (αν δεν έχεις το υλικό X, μπορείς να χρησιμοποιήσεις το Y). Βγάλε ένα αντικείμενο JSON που αντιστοιχίζει το συνιστώμενο υλικό με το υποκατάστατό του. Συμπεριλάβε τα προαιρετικά υλικά στην αντιστοίχιση.

Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα
jq Exercism

Έτοιμος να ξεκινήσεις την άσκηση Λίστα αγορών;

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