# Aula 2.4 - Arrays e transformação de dados

## Identificação

- **Duração:** 2 horas
- **Tipo:** teoria aplicada e laboratório
- **Entrega:** painel de métricas baseado em arrays
- **Laboratório:** [`../exemplos/aula-2.4/index.html`](../exemplos/aula-2.4/index.html)

## Introdução

### O que é um array?

Um array é uma estrutura do JavaScript usada para guardar uma sequência ordenada de
valores:

```js
const lessonNames = [
  "Valores e tipos",
  "Condições",
  "Funções",
];
```

Arrays são úteis quando precisamos representar vários itens relacionados, como
tarefas, usuários, mensagens ou aulas.

### Array é um banco de dados?

Não. Um array existe na memória enquanto o JavaScript está executando. Ao recarregar
a página, seus dados normalmente desaparecem.

Um banco de dados oferece persistência, consultas, controle de concorrência e outras
garantias. Mais adiante, utilizaremos MySQL para armazenar informações. Nesta aula,
o array será nossa coleção temporária para aprender a transformar dados.

### Array e objeto são a mesma coisa?

Um array representa uma coleção ordenada:

```js
const tasks = ["Estudar", "Praticar"];
```

Um objeto reúne propriedades de uma entidade:

```js
const task = {
  title: "Estudar",
  status: "doing",
};
```

Na prática, usaremos frequentemente um array de objetos:

```js
const tasks = [
  { title: "Estudar", status: "doing" },
  { title: "Praticar", status: "todo" },
];
```

Estudaremos objetos com mais profundidade na Aula 2.5.

### Por que o primeiro índice é zero?

O primeiro valor está na posição `0`:

```js
const colors = ["azul", "verde", "laranja"];

colors[0]; // "azul"
colors[1]; // "verde"
colors[2]; // "laranja"
```

Por isso, o último índice válido é `array.length - 1`.

### O que significa transformar dados?

Transformar dados é produzir uma nova representação a partir de uma coleção:

- selecionar somente tarefas abertas;
- converter tarefas em cartões;
- somar horas estimadas;
- ordenar por prioridade;
- descobrir se existe tarefa crítica.

JavaScript oferece métodos declarativos, como `map`, `filter`, `reduce` e `sort`.
Eles permitem expressar **o que** desejamos obter sem controlar manualmente cada
índice.

### Onde isso aparece no projeto?

Nesta aula, uma coleção de tarefas alimentará um painel. Os controles aplicarão um
fluxo de filtro, ordenação e cálculo de métricas sem alterar o array original.

## Objetivos

Ao final da aula, o aluno deverá conseguir:

1. criar e acessar arrays;
2. explicar `length` e índices;
3. adicionar e remover itens conscientemente;
4. percorrer arrays com `for...of` e `forEach`;
5. transformar valores com `map`;
6. selecionar valores com `filter`;
7. encontrar itens com `find`;
8. verificar coleções com `some` e `every`;
9. acumular resultados com `reduce`;
10. ordenar dados sem alterar o array original;
11. explicar mutação e imutabilidade;
12. encadear transformações legíveis.

## Pré-requisitos

- Aulas 2.1 a 2.3 concluídas;
- condições, repetições e funções;
- noções iniciais de objetos;
- navegador, DevTools e editor.

## Pergunta orientadora

> Como obter listas e métricas diferentes a partir dos mesmos dados sem destruir a coleção original?

## Roteiro sugerido

| Etapa | Duração |
|---|---:|
| Estrutura, índices e operações básicas | 25 min |
| Iteração e busca | 20 min |
| `map`, `filter` e `reduce` | 35 min |
| Ordenação e imutabilidade | 15 min |
| Laboratório | 20 min |
| Revisão | 5 min |

## 1. Criando arrays

```js
const emptyTasks = [];

const taskTitles = [
  "Revisar HTML",
  "Praticar JavaScript",
  "Publicar projeto",
];
```

Arrays podem tecnicamente misturar tipos:

```js
const mixedValues = ["texto", 42, true, null];
```

Entretanto, coleções com itens de formato consistente são mais previsíveis:

```js
const estimates = [1, 2, 5, 3];
```

## 2. Acesso, tamanho e limites

```js
const tasks = ["A", "B", "C"];

tasks.length; // 3
tasks[0]; // "A"
tasks[tasks.length - 1]; // "C"
tasks[10]; // undefined
```

`length` representa a posição seguinte ao último índice, não o último índice.

## 3. Verificando se é array

```js
Array.isArray([]); // true
Array.isArray({}); // false
```

`typeof` não diferencia corretamente:

```js
typeof []; // "object"
```

Para validar arrays, utilize `Array.isArray`.

## 4. Adicionar e remover

### Final da coleção

```js
const tasks = ["Estudar"];

tasks.push("Praticar");
const removed = tasks.pop();
```

- `push` adiciona ao final;
- `pop` remove e retorna o último item;
- ambos alteram o array original.

### Início da coleção

```js
tasks.unshift("Planejar");
const first = tasks.shift();
```

- `unshift` adiciona no início;
- `shift` remove do início;
- ambos alteram o array.

Alterações no início exigem reposicionar os índices existentes e podem ter custo
maior em coleções grandes.

## 5. Mutação e imutabilidade

Mutação altera o valor existente:

```js
const tasks = ["A", "B"];
tasks.push("C");
```

Criação imutável produz um novo array:

```js
const tasks = ["A", "B"];
const updatedTasks = [...tasks, "C"];
```

Imutabilidade ajuda a:

- comparar versões;
- evitar alterações distantes e inesperadas;
- preservar o estado anterior;
- trabalhar com frameworks que detectam novas referências.

Não significa que todo uso de `push` seja proibido. Significa compreender se a
operação altera a entrada e escolher conscientemente.

## 6. Cópia rasa com spread

```js
const original = ["A", "B"];
const copy = [...original];
```

Para objetos internos, a cópia é rasa:

```js
const original = [{ title: "Estudar" }];
const copy = [...original];

copy[0].title = "Alterado";
console.log(original[0].title); // "Alterado"
```

Os dois arrays são diferentes, mas ainda apontam para o mesmo objeto interno.

## 7. `for...of`

```js
for (const task of tasks) {
  console.log(task.title);
}
```

Use quando deseja controle de fluxo como `break`, `continue` ou `await`.

## 8. `forEach`

```js
tasks.forEach((task, index) => {
  console.log(index, task.title);
});
```

`forEach` executa um callback para cada item e retorna `undefined`. Ele é adequado
para efeitos, como registrar informações. Não é a escolha para criar um novo array.

Não é possível encerrar um `forEach` com `break`.

## 9. `map`

`map` transforma cada item e retorna um novo array com o mesmo tamanho:

```js
const tasks = [
  { title: "Estudar", estimate: 2 },
  { title: "Praticar", estimate: 3 },
];

const titles = tasks.map((task) => task.title);
// ["Estudar", "Praticar"]
```

Outro exemplo:

```js
const doubledEstimates = tasks.map((task) => task.estimate * 2);
```

Pergunta para reconhecer `map`:

> Quero converter cada item em outra representação?

## 10. Erro comum no `map`

Com chaves, use `return`:

```js
const titles = tasks.map((task) => {
  return task.title;
});
```

Sem retorno, o novo array conterá `undefined`:

```js
const titles = tasks.map((task) => {
  task.title;
});
```

Retorno implícito:

```js
const titles = tasks.map((task) => task.title);
```

## 11. `filter`

`filter` mantém os itens cujo callback retorna verdadeiro:

```js
const openTasks = tasks.filter((task) => task.status !== "done");
```

O resultado pode ter tamanho menor ou igual ao original.

```js
const criticalTasks = tasks.filter(
  (task) => task.priority === "critical",
);
```

Pergunta para reconhecer `filter`:

> Quero manter apenas os itens que atendem a uma condição?

## 12. `find` e `findIndex`

`find` retorna o primeiro item encontrado:

```js
const task = tasks.find((item) => item.id === 3);
```

Se nenhum item atender à condição, retorna `undefined`.

`findIndex` retorna o índice:

```js
const index = tasks.findIndex((item) => item.id === 3);
```

Se não encontrar, retorna `-1`.

Use `find` para um item; use `filter` para uma coleção de itens.

## 13. `some` e `every`

`some` responde se pelo menos um item atende à regra:

```js
const hasCriticalTask = tasks.some(
  (task) => task.priority === "critical",
);
```

`every` responde se todos atendem:

```js
const allTasksDone = tasks.every(
  (task) => task.status === "done",
);
```

Ambos retornam booleanos e podem parar assim que a resposta estiver determinada.

Em um array vazio:

```js
[].some(() => true); // false
[].every(() => false); // true
```

O resultado de `every` pode surpreender. Antes de exibir “todas concluídas”, confira
também se existem itens.

## 14. `includes`

```js
const allowedStatuses = ["todo", "doing", "done"];
const isAllowed = allowedStatuses.includes("doing");
```

Para objetos, `includes` compara a referência:

```js
const task = { id: 1 };
const tasks = [task];

tasks.includes(task); // true
tasks.includes({ id: 1 }); // false
```

Para procurar por propriedades, utilize `find` ou `some`.

## 15. `reduce`

`reduce` acumula os itens em um único resultado:

```js
const totalHours = tasks.reduce((total, task) => {
  return total + task.estimate;
}, 0);
```

Elementos:

- `total`: acumulador;
- `task`: item atual;
- `0`: valor inicial.

Evolução:

```text
0 + primeira estimativa
resultado + segunda estimativa
resultado + terceira estimativa
```

Sempre que possível, informe o valor inicial. Sem ele, arrays vazios podem causar
erro e o tipo inicial pode ficar menos evidente.

## 16. Métricas com `reduce`

Podemos calcular várias métricas em uma passagem:

```js
const metrics = tasks.reduce(
  (summary, task) => {
    summary.total += 1;
    summary.totalHours += task.estimate;

    if (task.status === "done") {
      summary.completed += 1;
    }

    return summary;
  },
  {
    total: 0,
    completed: 0,
    totalHours: 0,
  },
);
```

Essa versão altera o objeto acumulador criado para aquela redução. Também poderíamos
retornar um novo objeto a cada volta, com custo adicional. O importante é não
alterar as tarefas de entrada.

## 17. `sort` altera o array

```js
const numbers = [10, 2, 30];
numbers.sort();
// [10, 2, 30] em ordem de texto, não numérica
```

Para números:

```js
numbers.sort((a, b) => a - b);
```

E lembre: `sort` modifica o array.

Ordenação sem alterar a entrada:

```js
const sortedTasks = [...tasks].sort((a, b) => {
  return a.estimate - b.estimate;
});
```

Ambientes modernos também possuem `toSorted`, que retorna um novo array:

```js
const sortedTasks = tasks.toSorted(
  (a, b) => a.estimate - b.estimate,
);
```

Neste curso, a cópia com spread será utilizada enquanto consideramos compatibilidade
com navegadores.

## 18. Ordenação por prioridade

Podemos associar cada prioridade a um peso:

```js
const priorityWeight = {
  critical: 4,
  high: 3,
  planned: 2,
  low: 1,
};

const sorted = [...tasks].sort((a, b) => {
  return priorityWeight[b.priority] - priorityWeight[a.priority];
});
```

O comparador retorna:

- valor negativo: `a` vem antes;
- zero: mantém equivalência de ordem;
- valor positivo: `b` vem antes.

## 19. Encadeamento

Métodos que retornam arrays podem ser encadeados:

```js
const visibleTitles = tasks
  .filter((task) => task.status !== "done")
  .sort((a, b) => a.estimate - b.estimate)
  .map((task) => task.title);
```

Leia da esquerda para a direita:

1. selecione tarefas abertas;
2. ordene por estimativa;
3. extraia os títulos.

Evite cadeias longas demais. Use variáveis intermediárias quando elas explicarem as
etapas.

## 20. Fluxo do painel

O laboratório seguirá este fluxo:

```text
tasks
  → filter por status
  → cópia + sort
  → map para elementos visuais
  → reduce para métricas
```

O array `tasks` permanece na ordem original. O painel também exibirá essa ordem para
que possamos comparar entrada e resultado.

## 21. Laboratório guiado

Abra o [painel de métricas](../exemplos/aula-2.4/index.html).

### Etapa 1 — Filtre

Alterne entre todas, abertas e concluídas. Observe:

- o número de itens visíveis;
- a lista resultante;
- as etapas do fluxo.

### Etapa 2 — Ordene

Ordene por prioridade, estimativa e título. Confirme que a ordem original indicada
na página não muda.

### Etapa 3 — Analise métricas

As métricas são calculadas com `reduce` sobre os itens visíveis:

- total;
- concluídas;
- horas estimadas;
- existência de prioridade crítica.

### Etapa 4 — Inspecione o código

Localize:

- `filterTasks`;
- `sortTasks`;
- `calculateMetrics`;
- `renderTasks`;
- `some`, `filter`, `map`, `reduce` e `sort`.

## 22. Erros comuns

### Confundir item com índice

```js
tasks.map((index) => index.title);
```

O primeiro parâmetro é o item. Use nomes coerentes:

```js
tasks.map((task) => task.title);
```

### Não retornar no callback

```js
tasks.filter((task) => {
  task.status === "done";
});
```

Use:

```js
tasks.filter((task) => {
  return task.status === "done";
});
```

### Alterar o original com `sort`

```js
const sorted = tasks.sort(compareTasks);
```

Use uma cópia:

```js
const sorted = [...tasks].sort(compareTasks);
```

### Usar `map` apenas para efeitos

Se não utilizar o array retornado e deseja somente executar um efeito, `forEach` ou
`for...of` comunica melhor a intenção.

### Usar `reduce` para tudo

`reduce` é poderoso, mas um `filter` ou `map` simples costuma ser mais legível.
Escolha o método que expressa a operação.

## 23. Boas práticas

- mantenha itens com estrutura consistente;
- use `Array.isArray` para validar;
- escolha métodos pela intenção;
- não altere entradas de funções de transformação;
- copie antes de ordenar;
- forneça valor inicial ao `reduce`;
- nomeie acumulador e item claramente;
- divida fluxos complexos em etapas;
- trate arrays vazios;
- preserve regras puras separadas do DOM.

## 24. Exercícios

### Exercício 1 — Títulos

Use `map` para criar um array somente com os títulos.

### Exercício 2 — Pendências

Use `filter` para selecionar tarefas não concluídas.

### Exercício 3 — Busca

Use `find` para localizar uma tarefa por `id`.

### Exercício 4 — Verificações

Use `some` para descobrir se existe tarefa crítica e `every` para verificar se todas
estão concluídas.

### Exercício 5 — Soma

Use `reduce` para calcular o total de horas.

### Exercício 6 — Ordem imutável

Ordene por título sem modificar a coleção original.

## 25. Desafio

Amplie o laboratório:

- adicione filtro por prioridade;
- combine filtro de status e prioridade;
- exiba média de horas;
- crie agrupamento por status com `reduce`;
- mantenha a ordem original intacta;
- mostre um estado vazio quando nenhum item atender aos filtros.

## 26. Lista de verificação de conclusão

- [ ] Sei explicar array e índice.
- [ ] Sei diferenciar array e banco de dados.
- [ ] Consigo escolher entre `map`, `filter` e `reduce`.
- [ ] Sei quando usar `find`, `some` e `every`.
- [ ] Entendo que `sort` altera o array.
- [ ] Consigo ordenar uma cópia.
- [ ] Sei explicar cópia rasa.
- [ ] Consigo ler um fluxo encadeado.
- [ ] Testei filtros com resultado vazio.
- [ ] Confirmei que a entrada original foi preservada.

## 27. Critérios de avaliação

| Critério | Pontos |
|---|---:|
| Uso correto de métodos de array | 30 |
| Métricas com `reduce` | 20 |
| Ordenação sem mutar a entrada | 20 |
| Filtros e estados vazios | 15 |
| Funções puras e legibilidade | 10 |
| Acessibilidade | 5 |
| **Total** | **100** |

## Resumo

Nesta aula, aprendemos que:

- arrays representam sequências ordenadas;
- índices começam em zero;
- `map` transforma, `filter` seleciona e `reduce` acumula;
- `find`, `some` e `every` respondem perguntas sobre a coleção;
- `sort` altera o array e deve ser aplicado a uma cópia quando desejamos preservar
  a entrada;
- fluxos convertem os mesmos dados em diferentes visualizações e métricas.

## Próxima aula

Na Aula 2.5, aprofundaremos objetos, desestruturação, cópias, modelagem de entidades
e conversão entre objetos JavaScript e JSON.
