You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: chapters/04-estruturas-de-dados.md
+102-1Lines changed: 102 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -665,4 +665,105 @@ Pode ser útil usar um valor de incremento diferente do valor padrão (por exemp
665
665
666
666
Os arrays possuem o método `reverse`, que modifica o array invertendo a ordem que os elementos aparecem. Para esse exercício, escreva duas funções: `reverseArray` e `reverseArrayInPlace`. A primeira (`reverseArray`) recebe um array como argumento e produz um _novo_ array que tem os mesmos elementos com ordem inversa. A segunda (`reverseArrayInPlace`) funciona da mesma forma que o método `reverse`, invertendo seus elementos apenas modificando o array que foi fornecido como argumento. Ambas as funções não devem usar o método padrão `reverse`.
Levando em consideração as notas sobre efeitos colaterais e funções puras do [capítulo anterior](./03-funcoes.md), qual variante você espera que seja útil em mais situações? Qual delas é mais eficiente?
669
+
670
+
```js
671
+
// Your code here.
672
+
673
+
console.log(reverseArray(["A", "B", "C"]));
674
+
// → ["C", "B", "A"];
675
+
var arrayValue = [1, 2, 3, 4, 5];
676
+
reverseArrayInPlace(arrayValue);
677
+
console.log(arrayValue);
678
+
// → [5, 4, 3, 2, 1]
679
+
```
680
+
681
+
**Dicas**
682
+
683
+
Existem duas maneiras óbvias de implementar `reverseArray`. A primeira é simplesmente iterar o array fornecido do início ao fim e usar o método `unshift` para inserir cada elemento no início do novo array. A segunda é iterar o array fornecido do fim ao início e usar o método `push`. Iterar um array de trás para frente faz com que seja necessário usar uma notação `for` um pouco estranha (`var i = array.length - 1; i >= 0; i--`).
684
+
685
+
Inverter o array em questão (`reverseArrayInPlace`) é mais difícil. Você deve ter cuidado para não sobrescrever elementos que você precisará posteriormente. Usar `reverseArray` ou até mesmo copiar o array inteiro (`array.slice(0)` é uma boa forma de se copiar um array) funciona mas é considerado trapaça.
686
+
687
+
O truque é _inverter_ o primeiro e o último elemento, depois o segundo e o penúltimo e assim por diante. Você pode fazer isso percorrendo até a metade do valor de `length` do array (use `Math.floor` para arredondar o valor para baixo — você não precisa usar o elemento do meio de um array com tamanho ímpar) e substituir o elemento na posição `i` com o elemento na posição `array.length - 1 - i`. Você pode usar uma variável local para armazenar temporariamente um dos elementos, sobrescrever o seu valor com o valor do elemento espelhado (elemento que deseja substituir), e por fim, colocar o valor da variável local no lugar onde o elemento espelhado estava originalmente.
688
+
689
+
### A lista
690
+
691
+
Objetos como agrupamentos genéricos de valores, podem ser usados para construir diversos tipos de estrutura de dados. Uma estrutura de dado comum é a _lista_ (não se confunda com o array). A lista é um conjunto de objetos, sendo que o primeiro objeto contém uma referência para o segundo, o segundo para o terceiro, e assim por diante.
692
+
693
+
```js
694
+
var list = {
695
+
value:1,
696
+
rest: {
697
+
value:2,
698
+
rest: {
699
+
value:3,
700
+
rest:null
701
+
}
702
+
}
703
+
};
704
+
```
705
+
706
+
O resultado desses objetos forma uma corrente, como representado abaixo:
Uma das vantagens das listas é que elas podem compartilhar partes de sua estrutura. Por exemplo, se eu criasse dois novos valores `{value: 0, rest: list}` e `{value: -1, rest: list}` (sendo que `list` é uma referência à variável definida anteriormente), ambas serão listas independentes que compartilham a mesma estrutura que foi usada para criar os três últimos elementos. Além disso, a lista original ainda é uma lista válida com três elementos.
711
+
712
+
Escreva a função `arrayToList` que constrói uma estrutura de dados similar à estrutura anterior quando fornecido `[1, 2, 3]` como argumento e, escreva também, a função `listToArray` que produz um array quando dado uma lista. Além disso, implemente uma função auxiliar `prepend` que receberá um elemento e uma lista e será responsável por criar uma nova lista com esse novo elemento adicionado ao início da lista original e, por fim, crie a função `nth` que recebe uma lista e um número como argumentos e retorna o elemento que está na posição informada pelo número ou `undefined` caso não exista elemento em tal posição.
713
+
714
+
Caso não tenha feito, implemente a versão recursiva da função `nth`.
Construir uma lista é mais fácil de ser feito de trás para frente. Portanto, `arrayToList` poderia percorrer o array de trás para frente (veja o exercício anterior) e, para cada elemento, adicionar um objeto à lista. Você pode usar uma variável local para armazenar a parte da lista que foi criada e usar um padrão similar a `list = {value: X, rest: list}` para adicionar um elemento.
732
+
733
+
Para percorrer uma lista (no caso de `listToArray` e `nth`), o seguinte loop `for` pode ser usado:
734
+
735
+
```js
736
+
for (var node = list; node; node =node.rest) {}
737
+
```
738
+
739
+
Você consegue ver como funciona? A cada iteração do loop, `node` aponta para a próxima sublista e, por isso, o corpo da função pode acessar a propriedade `value` para pegar o elemento atual. Ao final de cada iteração, `node` é atualizado apontando para a próxima sublista. Quando seu valor é `null`, nós chegamos ao final da lista e o loop é finalizado.
740
+
741
+
A versão recursiva de `nth` irá, similarmente, olhar para uma parte ainda menor do _tail_ (final) da lista e, ao mesmo tempo, fazer a contagem do índice até que chegue a zero, significando que é o ponto no qual pode retornar a propriedade `value` do nó que está sendo verificado. Para pegar o elemento na posição zero de uma lista, você pode simplesmente acessar a propriedade `value` do seu nó _head_ (inicial). Para pegar o elemento `N + 1`, você pega o n-ésimo elemento da lista que está contido na propriedade `rest` da lista em questão.
742
+
743
+
### Deep comparison
744
+
745
+
O operador `==` compara objetos pelas suas identidades. Entretanto, algumas vezes você pode preferir comparar os valores das suas propriedades de fato.
746
+
747
+
Escreva a função `deepEqual` que recebe dois valores e retorna `true` apenas se os valores forem iguais ou se forem objetos que possuem propriedades e valores iguais quando comparados usando uma chamada recursiva de `deepEqual`.
748
+
749
+
Para saber se a comparação entre duas coisas deve ser feita pela identidade (use o operador `===` para isso) ou pela verificação de suas propriedades, você pode usar o operador `typeof`. Se ele produzir `object` para ambos os valores, você deverá fazer uma comparação "profunda". Entretanto, você deve levar em consideração uma excessão: devido a um acidente histórico, `typeof null` também produz `object`.
O teste para saber se está lidando com um objeto real deverá ser parecido com `typeof x == "object" && x != null`. Tome cuidado para comparar as propriedades apenas quando ambos argumentos forem objetos. Em todos os outros casos, você pode simplesmente retornar imediatamente o resultado da aplicação de `===`.
766
+
767
+
Use um loop `for/in` para percorrer todas as propriedades. Você precisa verificar se ambos os objetos possuem o mesmo conjunto de propriedades e se essas propriedades têm valores idênticos. O primeiro teste pode ser feito contando a quantidade de propriedades em cada objeto e retornar `false` se forem diferentes. Caso seja o mesmo, percorra todas as propriedades de um objeto e, para cada uma delas, verifique se o outro objeto também a possui. Os valores das propriedades são comparados usando uma chamada recursiva para `deepEqual`.
768
+
769
+
Para retornar o valor correto da função, é mais fácil retornar imediatamente `false` quando qualquer diferença for encontrada e retornar apenas `true` ao final da função.
0 commit comments