Um objeto JSON é, para usar terminologia de outras linguagens, uma "hash", um "map" ou um "dicionário".
O JSON define um objeto como:
Um objeto é um conjunto não ordenado de pares nome/valor. Um objeto começa com
{chaveta esquerda e termina com}chaveta direita. Cada nome é seguido de:dois pontos e os pares nome/valor são separados por,vírgula.
O nome tem de ser uma string. Outra palavra para nome é chave.
O valor pode ser de qualquer tipo JSON. Diferentes valores no mesmo objeto podem ser de tipos diferentes, como neste exemplo.
{
"name": "Jane",
"age": 42,
"pets": ["cat", "fish"],
"address": {"street": "123 Main St", "city": "Springfield"}
}
Repara que não pode haver uma vírgula a seguir ao último par chave-valor.
Usa chavetas para reunir os pares nome/valor. Embora os nomes tenham de ser strings, não precisam de estar entre aspas se forem semelhantes a identificadores (compostos por carateres alfanuméricos e underscores, e não começarem por um algarismo).
{name: "Jane", age: 42}
É válido usar chaves que não sejam semelhantes a identificadores. Basta colocá-las entre aspas.
{"first name": "Jane", "last name": "Lopez", age: 42}
Se o nome for o resultado de uma expressão, a expressão tem de estar entre parênteses.
$ echo "Jane" | jq -Rc '{.: 42}'
# verbose error message ...
$ echo "Jane" | jq -Rc '{(.): 42}'
{"Jane":42}
Os valores são obtidos de um objeto com notação de ponto.
{name: "Jane", age: 42} | .age # => 42
Se não conseguires referir-te à chave como um identificador, usa notação de parênteses retos.
"name" as $key | {name: "Jane", age: 42} | .$key # => error
"name" as $key | {name: "Jane", age: 42} | .[$key] # => "Jane"
Para adicionares um novo par chave-valor a um array, ou para atualizares o valor de uma chave existente, usa o operador de atribuição =, com uma expressão de índice do lado esquerdo.
{name: "Jane", age: 42} | .sport = "tennis" | .age = 21
# => {
# "name": "Jane",
# "age": 21,
# "sport": "tennis"
# }
O operador + funde objetos.
{Richard: 54} + {Jane: 42}
# => {
# "Richard": 54,
# "Jane": 42
# }
Usa a função del para remover uma chave.
Devolve o objeto atualizado.
{name: "Jane", age: 42} | del(.age) # => {"name": "Jane"}
O parâmetro de del é uma expressão de índice (com notação de ponto ou de parênteses retos) que se resolve numa chave do objeto.
O jq chama-lhe uma expressão de caminho.
Não basta dar apenas uma string.
{name: "Jane", age: 42} | del(name) # error: name/0 is not defined
{name: "Jane", age: 42} | del("name") # error: Invalid path expression with result "name"
{name: "Jane", age: 42} | del(.name) # OK
{name: "Jane", age: 42} | del(.["name"]) # OK
Para testar se o objeto tem uma chave, usa a função has.
{name: "Jane", age: 42} as $example
|
($example | has("name")), # => true
($example | has("sport")) # => false
Testa se uma chave está num objeto com in.
{name: "Jane", age: 42} as $example
|
("name" | in($example)), # => true
("sport" | in($example)) # => false
Usa a função keys para devolver uma lista de todas as chaves.
{name: "Jane", age: 42} | keys # => ["age", "name"]
Repara que keys ordena as chaves.
Para obteres as chaves na ordem original, usa keys_unsorted.
Não existe uma função equivalente para listar todos os valores.
No entanto, o filtro .[] devolve os valores do objeto como um fluxo, e esse fluxo pode ser capturado com o construtor de arrays [...].
[{first: "Jane", last: "Lopez", status: "awesome!"} | .[]]
# => ["Jane", "Lopez", "awesome!"]
A função map_values(filter) aplica o filtro a cada valor do objeto.
{first: "Jane", last: "Lopez", status: "awesome!"}
| map_values(ascii_upcase)
# => {"first": "JANE", "last": "LOPEZ", "status": "AWESOME!"}
Para iterar sobre um objeto, temos de o converter primeiro num array de objetos chave-valor.
A função to_entries faz isso.
{name: "Jane", age: 42} | to_entries'
# => [
# {
# "key": "name",
# "value": "Jane"
# },
# {
# "key": "age",
# "value": 42
# }
# ]
Neste ponto, podemos usar funções de iteração de arrays, como map.
A função from_entries é a inversa: converte um array de objetos chave-valor num objeto.
[
{"key":"name", "value":"Jane"},
{"key":"age", "value":42}
] | from_entries # =>{"name": "Jane", "age": 42}
Para aplicares um filtro a cada par chave-valor de um objeto, usa a função with_entries(filter).
Por exemplo, dado um objeto que associa um nome a uma idade, as chaves e os valores podem ser trocados da seguinte forma.
{"Jane": 42, "Richard": 54}
| with_entries({key: (.value | tostring), value: .key})
devolve
{
"42": "Jane",
"54": "Richard"
}
with_entries(filter) é o mesmo que
to_entries | map(filter) | from_entries
Neste exercício, vais implementar uma forma de acompanhar as pontuações máximas do jogo mais popular do salão de jogos da tua zona.
Tens 6 funções para implementar, a maioria relacionada com a manipulação de um objeto que guarda pontuações máximas.
Escreve uma função create_score_board que cria um objeto que serve de tabela de pontuações máximas.
As chaves deste objeto serão os nomes dos jogadores e os valores serão as suas pontuações.
Para efeitos de teste, queres incluir diretamente uma entrada no objeto.
Esta entrada inicial deve consistir em "The Best Ever" como nome do jogador e 1000000 como pontuação.
create_score_board
# returns an object with one initial entry
Para adicionar um jogador à tabela de pontuações máximas, implementa a função add_player.
Recebe uma tabela de pontuações como entrada e precisa de dois parâmetros: o nome do jogador e a pontuação do jogador.
A função devolve o objeto da tabela de pontuações com o novo jogador adicionado.
{"José Valim", 486373}
| add_player("Dave Thomas"; 0)
# => {"Dave Thomas": 0, "José Valim": 486373} -- in some order
Se o jogador já estiver na tabela, devolve a tabela sem alterações.
Se os jogadores violarem as regras do salão de jogos, são removidos manualmente da tabela de pontuações máximas.
Implementa remove_player, que recebe uma tabela como entrada e um parâmetro, o nome do jogador a remover.
Esta função deve remover a entrada do jogador indicado da tabela e devolver a nova tabela.
Se o jogador não estiver na tabela, não deve acontecer nada à tabela; deve ser devolvida tal como está.
{"Dave Thomas": 0} | remove_player("Dave Thomas")
# => {}
{"Dave Thomas": 0} | remove_player("Rose Fanaras")
# => {"Dave Thomas": 0}
Se um jogador terminar outro jogo no salão de jogos, uma certa quantidade de pontos será adicionada à pontuação anterior na tabela.
Implementa update_score, que recebe uma tabela de pontuações como entrada e precisa de dois parâmetros: o nome do jogador e a quantidade de pontos a adicionar.
A função deve devolver a tabela de pontuações depois de feita a atualização.
{"Freyja Ćirić": 12771000} | update_score("Freyja Ćirić"; 73)
# => {"Freyja Ćirić": 12771073}
Esta função deve adicionar o jogador à tabela, caso ainda não esteja nela.
O salão de jogos tem uma tabela de pontuações separada às segundas-feiras. No fim do dia, cada jogador dessa tabela recebe 100 pontos adicionais.
Implementa a função apply_monday_bonus.
A função adiciona os pontos de bónus a cada jogador que esteja listado nessa tabela.
{
"Dave Thomas": 44,
"Freyja Ćirić": 539,
"José Valim": 265
}
| apply_monday_bonus
# => {"Dave Thomas": 144, "Freyja Ćirić": 639, "José Valim": 365}
Diferentes salões de jogos competem entre si para determinar quem tem os melhores jogadores. O salão com a pontuação total mais alta ganha a honra.
Escreve uma função total_score.
Recebe uma tabela de pontuações como entrada e devolve a soma das pontuações de todos os jogadores.
{
"Dave Thomas": 44,
"Freyja Ćirić": 539,
"José Valim": 265
}
| total_score
# => 848
Inscreve-te no Exercism para aprenderes e dominares jq com 12 conceitos75 exercícios, e mentoria humana real, tudo grátis.