Maquinista

Maquinista

Exercício de aprendizagem

Introdução

O JavaScript tem um operador ... incorporado que facilita o trabalho com um número indefinido de elementos. Consoante o contexto, chama-se operador rest ou operador spread.

Operador rest

Elementos rest

Quando o ... aparece do lado esquerdo de uma atribuição, esses três pontos são conhecidos como o operador rest. Os três pontos, em conjunto com o nome de uma variável, formam aquilo a que se chama um elemento rest. Recolhe zero ou mais valores e guarda-os num único array.

const [a, b, ...everythingElse] = [0, 1, 1, 2, 3, 5, 8];
a;
// => 0
b;
// => 1
everythingElse;
// => [1, 2, 3, 5, 8]

Repara que em JavaScript, ao contrário de algumas outras linguagens, um elemento rest não pode ter uma vírgula final. Tem obrigatoriamente de ser o último elemento numa atribuição por desestruturação. O exemplo abaixo lança um SyntaxError:

const [...items, last] = [2, 4, 8, 16]

Propriedades rest

Tal como acontece com os arrays, o operador rest também pode ser utilizado para recolher uma ou mais propriedades de um objeto e guardá-las num único objeto.

const { street, ...address } = {
  street: 'Platz der Republik 1',
  postalCode: '11011',
  city: 'Berlin',
};
street;
// => 'Platz der Republik 1'
address;
// => {postalCode: '11011', city: 'Berlin'}

Parâmetros rest

Quando o ... aparece na definição de uma função, ao lado do seu último argumento, esse parâmetro chama-se parâmetro rest. Permite que a função aceite um número indefinido de argumentos na forma de um array.

function concat(...strings) {
  return strings.join(' ');
}
concat('one');
// => 'one'
concat('one', 'two', 'three');
// => 'one two three'

Spread

Elementos spread

Quando o ... aparece do lado direito de uma atribuição, é conhecido como o operador spread. Expande um array numa lista de elementos. Ao contrário do elemento rest, pode aparecer em qualquer posição de uma expressão literal de array e pode haver mais do que um.

const oneToFive = [1, 2, 3, 4, 5];
const oneToTen = [...oneToFive, 6, 7, 8, 9, 10];
oneToTen;
// => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const woow = ['A', ...oneToFive, 'B', 'C', 'D', 'E', ...oneToFive, 42];
woow;
// =>  ["A", 1, 2, 3, 4, 5, "B", "C", "D", "E", 1, 2, 3, 4, 5, 42]

Propriedades spread

Tal como acontece com os arrays, o operador spread também pode ser utilizado para copiar propriedades de um objeto para outro.

let address = {
  postalCode: '11011',
  city: 'Berlin',
};
address = { ...address, country: 'Germany' };
// => {
//   postalCode: '11011',
//   city: 'Berlin',
//   country: 'Germany',
// }

Instruções

O teu amigo Linus é maquinista e conduz comboios de mercadorias entre cidades. Apesar de ser fantástico a conduzir comboios, não é tão bom com logística ou computadores. Gostaria de contar com a tua ajuda na programação para organizar os detalhes dos comboios e corrigir erros nos dados das rotas.

Note

Para praticar, usa o operador rest ou spread para resolver cada uma das tarefas abaixo.

1. Cria uma lista com todos os vagões

O teu amigo tem registado o identificador (ID) de cada vagão, mas nunca sabe quantos vagões é que o sistema vai ter de processar em cada momento. Seria muito mais fácil para o resto do programa de logística ter estes dados reunidos num único array.

Implementa uma função getListOfWagons que aceita um número arbitrário de IDs de vagões, que são os IDs de cada vagão. Cada ID será um número inteiro positivo. A função deve depois devolver os IDs recebidos num único array.

getListOfWagons(1, 7, 12, 3, 14, 8, 5);
// => [1, 7, 12, 3, 14, 8, 5]

2. Move os dois primeiros elementos para o fim do array

A esta altura, já estás a começar a perceber os dados e a forma como são usados no programa de logística. O sistema de IDs atribui sempre à locomotiva o ID 1, e aos restantes vagões do comboio atribui um ID escolhido aleatoriamente maior do que 1.

O teu amigo teve de ligar dois vagões novos ao comboio e esqueceu-se de atualizar o sistema! Agora, os dois primeiros vagões do array do comboio têm de ser movidos para o fim, senão fica tudo fora de ordem.

O Linus ficaria muito grato se corrigisses os erros dele.

Implementa uma função fixListOfWagons que aceita um array com o id de cada vagão. return de um array onde os 2 primeiros elementos são reposicionados no fim do array, para que a locomotiva possa ficar à frente.

eachWagonsID = [2, 5, 1, 7, 4, 12, 6, 3, 13];
fixListOfWagons(eachWagonsID);
// => [1, 7, 4,  12, 6, 3, 13, 2, 5]

3. Adiciona os valores em falta

Ora, bolas. Parece que alguns vagões desapareceram.

Felizmente, o teu amigo acabou de encontrar outro array que parece conter os IDs dos vagões em falta, e gostaria que os adicionasses ao array principal de IDs dos vagões. A única coisa de que se lembra é que os valores em falta devem ser colocados imediatamente a seguir à locomotiva designada.

Com esta nova informação, escreve uma função chamada correctListOfWagons que recebe como argumentos dois arrays com os IDs de cada vagão. Os IDs dos vagões do segundo array devem ser adicionados ao primeiro array, imediatamente a seguir à locomotiva (ID 1).

eachWagonsID = [1, 5, 20, 7, 4, 8];
missingWagons = [3, 17, 6, 15];
correctListOfWagons(eachWagonsID, missingWagons);
// => [1, 3, 17, 6, 15, 5, 20, 7, 4, 8]

4. Estende a informação de rotas

Agora que todos os dados dos vagões estão corretos, o teu amigo gostaria que atualizasses a informação de rotas do sistema. A informação de rotas inicial foi construída como um object, e o teu amigo gostaria que a atualizasses com os acrescentos fornecidos. Cada rota exige informação um pouco diferente, por isso o teu amigo preferia mesmo uma solução genérica.

Implementa uma função extendRouteInformation que aceita dois objects. O primeiro object contém as cidades entre as quais o comboio circula.

O segundo object contém outros detalhes da rota, como a velocidade ou o comprimento do comboio. A função deve devolver um object consolidado com toda a informação de rotas.

Note

A variável moreRouteInformation pode conter propriedades diferentes.

route = { from: 'Berlin', to: 'Hamburg' };
moreRouteInformation = { length: '100', speed: '50' };
extendRouteInformation(route, moreRouteInformation);
// => {from: "Berlin", to: "Hamburg", length: "100", speed: "50"}

5. Separa a hora de chegada da informação de rotas

O teu amigo reparou que não precisa da hora de chegada na informação de rotas. Por isso, gostaria que separasses a hora de chegada da informação de rotas.

Implementa uma função separateTimeOfArrival que aceita um object com a informação de rotas. A função deve devolver um array em que o primeiro elemento é a hora de chegada e o segundo é um object com a informação de rotas sem a hora de chegada.

routeInformation = {
  from: 'Berlin',
  to: 'Hamburg',
  length: '100',
  timeOfArrival: '10:10',
};
separateTimeOfArrival(routeInformation);
// => ["10:10", {from: "Berlin", to: "Hamburg", length: "100"}]
Editar via GitHub A ligação abre numa nova janela ou separador
JavaScript Exercism

Estás pronto para começar Maquinista?

Inscreve-te no Exercism para aprenderes e dominares JavaScript com 37 conceitos159 exercícios, e mentoria humana real, tudo grátis.