Percursos
/
jq
jq
/
Exercícios
/
Quadro de Recordes
Quadro de Recordes

Quadro de Recordes

Exercício de aprendizagem

Introdução

Objetos

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.

Criar objetos

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}

Indexação

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"

Adicionar ou alterar pares chave-valor

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
#    }

Remover uma chave

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

Pertinência

  • 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
    

Listar todas as chaves

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!"]

Iterar

  • 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
    

Instruções

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.

1. Cria uma nova tabela de 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

2. Adiciona jogadores a uma tabela de pontuações

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.

3. Remove jogadores de uma tabela de pontuaçõ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}

4. Aumenta a pontuação de um jogador

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.

5. Aplica os pontos de bónus de segunda-feira

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}

6. Encontra a pontuação total

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
Editar via GitHub A ligação abre numa nova janela ou separador
jq Exercism

Estás pronto para começar Quadro de Recordes?

Inscreve-te no Exercism para aprenderes e dominares jq com 12 conceitos75 exercícios, e mentoria humana real, tudo grátis.