Kurzusok
/
jq
jq
/
Feladatok
/
Bevásárlólista
Bevásárlólista

Bevásárlólista

Tanulófeladat

Bevezetés

Alapok

Feltételezzük, hogy ismered a JSON szintaxisát és adattípusait.

A jq úgy működik, hogy a beérkező JSON adatot egy kifejezésen (amely szűrők csővezetékeként íródik le) vezeti át, hogy elérje a kívánt átalakított adatot.

Note

A jq nyelvet a jq program valósítja meg. Ez a program több hasznos parancssori kapcsolót kínál, amelyekkel szabályozhatod, hogyan fogyasztja a bemenetet és hogyan jeleníti meg a kimenetet.

Az alábbi példákban ezekkel találkozol majd:

  • -n vagy --null-input

    A jq program általában egy fájlt kap, amit beolvas, vagy adatot küldesz a bemenetére. A --null-input kapcsolóval bemenet nélkül is generálhatsz JSON adatot.

  • -c vagy --compact-output

    A jq alapértelmezés szerint szépen formázva írja ki a kimenetét. Rendkívül hasznos az emberek számára, ha az adat szépen formázva jelenik meg. A gépeknek azonban erre nincs szükségük: a --compact-output kapcsoló eltávolítja a formázó whitespace-t, hogy a keletkező JSON mérete a lehető legkisebb legyen.

  • -f filename vagy --from-file filename

    A jq programot a filename nevű fájlból olvassa be ahelyett, hogy a parancssorban adnád meg. A sed és az awk is ugyanerre a célra használja a -f kapcsolót. Ezzel a gyakorlófeladatok tesztszkriptjeiben találkozol majd.

A lecke további része a jq nyelvére összpontosít.

Szűrők és csövek

A szűrőket kifejezéseknek is nevezik.

Egy szűrő bemenetet vesz és kimenetet állít elő. Ahogy a unix shellben dolgozol, a szűrőket itt is összefűzheted egy | csővezetékkel, hogy az egyik szűrő kimenetét a másik bemenetéhez kapcsold.

Az identitásszűrő: .

Ez a legegyszerűbb szűrő. Egyszerűen átadja a bemenetét a kimenetének.

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

Tömbök

Ez egy gyors bevezetés a tömbökkel való munkába. Ezt a témát később részletesebben is tárgyaljuk.

A tömb elemeihez szögletes zárójellel férsz hozzá, és az indexelés nullától indul.

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

Egy szűrő úgy építhet tömböt, hogy egy kifejezést [ és ] közé zár

  • ismert elemlistával:

    jq -n '[1, 2, 3]'
    
  • elemfolyam összegyűjtéséhez: például a range egy függvény, amely számok folyamát adja ki

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

    A [] használatával a kifejezés eredményei egy tömbbe gyűlnek

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

A vessző operátor

A vessző nem csupán olyan szintaxis, amely elválasztja a tömb elemeit. A vessző egy operátor, amely folyamokat fűz össze.

Például a [1, 2, 3] egy szűrő, amely a [] tömbkonstruktort használja, hogy összegyűjtse a 1, 2 és 3 kifejezés összefűzésének eredményét.

Észrevetted a pontosvesszőket a fenti range(10; 70; 15) kifejezésben? Mivel a vesszőknek meghatározott szerepük van a jq nyelvben, a több argumentumot fogadó függvények pontosvesszővel választják el az argumentumokat.

Objektumok

Gyors bevezetés az objektumokba.

A sok programozási nyelvhez hasonlóan ponttal férsz hozzá az objektum tulajdonságaihoz

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

Szögletes zárójeleket az objektumoknál is használhatsz, de akkor az idézőjelek kötelezők a string literálokhoz. Ez az egyik módja annak, hogy szóközt tartalmazó kulcsokkal dolgozz.

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

Egy objektumot {} és key: value párokkal hozhatsz létre. Az olyan kulcsok körül, amelyek „egyszerű” stringek, nem kötelezők az idézőjelek.

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

az alábbi kimenetet adja

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

Ahhoz, hogy a kulcsot kifejezésként kezeld, zárójelbe kell tenned (a következő is ugyanazt adja eredményül, mint a fenti).

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

Csővezetékek

Például ha a file.json a következőt tartalmazza

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

Számítsuk ki a key2 tömb hosszát:

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

A .key2 kifejezés kimenetét csővezetéken adjuk tovább a length bemenetének, amely nem meglepő módon a tömb elemeinek számát adja ki.

A szűrők figyelmen kívül hagyhatják a bemenetüket

Ebben a példában a bemenő JSON adatot figyelmen kívül hagyjuk, és nincs hatással a kimenetre:

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

A szűrők adatfolyamokat adhatnak ki

Egy szűrő egynél több értéket is kiadhat. Például a .[] szűrő a tömb minden elemét külön értékként adja ki:

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

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

Ha egy ilyen szűrőt egy másikba vezetsz, a második szűrő minden egyes értékre lefut:

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

Ez olyan, mint az implicit iteráció. Ha egyszer megérted ezt a technikát, rájössz, hogy a nagyon erős jq szűrők is lehetnek nagyon tömörek.

Zárójelek

A zárójelekkel részkifejezéseket csoportosíthatsz, hogy érvényre juttasd a műveletek sorrendjét, akárcsak más nyelvekben. A jq-ban néha meglepőnek tűnhet, hogy szükség van rájuk.

Tegyük fel például, hogy egy kételemű tömböt szeretnénk létrehozni: a 9 négyzetgyökét és az 1. hatványra emelt e-t. A két külön kifejezés a 9 | sqrt és az 1 | exp. Azt várjuk, hogy a kimenet a [3, 2.7...] tömb lesz

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

Miért nem azt kaptuk, amire számítottunk? A jq így értelmezi:

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

A jq kételemű folyamot épít (3 és 1), amelyeket egyenként megkap az exp.

Gondoskodnunk kell róla, hogy az exp csak egy számot kapjon bemenetként. Más szóval el kell érnünk, hogy a csővezeték kiértékelése megelőzze a vesszőét.

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

Függvények és operátorok

Anélkül, hogy túl mélyre mennénk (a függvények egy másik feladat témáját képezik majd), íme néhány hasznos beépített függvény:

  • length

    Ha egy tömböt kap bemenetként, adja ki a tömb elemeinek számát.

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

    Ez az operátor az operandusai típusától függően mást és mást tesz: összeadja a számokat, összefűzi a stringeket, hozzáfűzi a tömböket, egyesíti az objektumokat.

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

    Az add egy függvény, amely egy tömböt kap, és egy olyan elemet ad vissza, amelyben az összes elem össze van adva a + szabályai szerint. A [1, 2, 3] | add kimenete 6.

  • map

    Ha bemenetként egy tömböt és argumentumként egy szűrőt kap, adjon ki egy tömböt, amelyben a szűrő minden elemre alkalmazva van

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

    Ha valamilyen bemenetet és argumentumként egy szűrőt kap:

    • ha az argumentumra alkalmazott szűrő igaz értéket ad, a bemenetet változatlanul adja ki
    • egyébként semmit nem ad ki (nem a null értéket, hanem tényleg semmilyen kimenetet)

    Például ha adott néhány szám, válaszd ki a 3-mal oszthatókat

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

    Emlékezz rá, hogy a range számok folyamát adja ki. A select minden számra egyszer hívódik meg. Csak azok a számok jelennek meg a kimenetben, amelyek „átmennek” a kifejezésen.

    Gyakran kell egy tömb elemeit kiválasztanod. Erre néhány mód kínálkozik.

    A ["Anne", "Bob", "Cathy", "Dave"] bemenettel válaszd ki a 4 hosszúságú neveket.

    • használd a map és a select függvényt együtt

      map(select(length == 4))
      
    • bontsd fel a tömböt elemekre, alkalmazd a select függvényt erre a folyamra, és gyűjtsd össze az eredményeket

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

Megjegyzések

A megjegyzések egy # karakterrel kezdődnek, és a sor végéig tartanak.

Utasítások

Hirtelen megkívántad a palacsintát. Modern, technikailag fogékony emberként JSON formátumban írod meg a palacsinta hozzávalóinak bevásárlólistáját. A lista felépítése a következő:

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

Egy hozzávalót JSON-objektumként ábrázolunk, például így:

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

Egy hozzávalónak lehet egy "substitute" nevű opcionális tulajdonsága, amelyben egy másik, helyette használható összetevő neve szerepel stringként.

Nézzük meg, hogyan vizsgálhatjuk meg a bevásárlólistát a jq segítségével!

1. A bevásárlólista nevének kinyerése

Írj egy kifejezést, amely kiírja a bevásárlólista "name" elemét!

2. A szükséges hozzávalók megszámolása

Csak a "required" hozzávalókat számold. Az opcionális hozzávalókat ne vedd bele.

3. Mennyi cukor?

Írj egy kifejezést, amely kiírja a cukor mennyiségét! Csak a számértékre van szükség.

4. A helyettesíthető hozzávalók leképezése

Néhány hozzávaló helyettesíthető (ha nincs meg az X hozzávaló, használhatod helyette az Y-t). Adj ki egy JSON-objektumot, amely az ajánlott hozzávalót a helyettesítőjéhez rendeli. Az opcionális hozzávalókat is vedd bele a leképezésbe.

Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg
jq Exercism

Készen állsz elkezdeni a(z) Bevásárlólista feladatot?

Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) jq nyelvet 12 fogalom75 feladat segítségével, valódi emberi mentorálással, mindez ingyen.