Adicionar novos elementos em um array

12/03/2020

0

Olá galera!

Estou tentando adicionar novos elementos em um array.
Entretanto, se o elemento a ser adicionado no array já existir, gostaria que a função procurasse outro elemento para adicionar, e que a mesma só fosse encerrada após conseguir adicionar um elemento novo.

Eu tenho dois objetos:
const allMaps = {
  Stage0: null,
  Stage1: [5,6,7,8,9],
  Stage2: [11,12,13,14,15],
  Stage3: [17,18,19,20,21],
  Stage4: [23,24,25,26,27],
  Stage5: [29,30,31,32,33],
  Stage6: [35,36,37,38,39]
}

let playedMaps = {
  Stage0: null,
  Stage1: [],
  Stage2: [],
  Stage3: [],
  Stage4: [],
  Stage5: [],
  Stage6: []
}


Na função "addPlayedMaps(stage)" a seguir, eu quero adicionar um único valor de allMaps.Stage1 para o playedMaps.Stage1.


function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max + 1);
    return Math.floor(Math.random() * (max - min)) + min;
};

function addPlayedMaps(stage){
for(let i = getRandomInt(5, 9); playedMaps[stage].indexOf(i) === -1; i = getRandomInt(5, 9) ){
    playedMaps[stage].push(i);
}
    return playedMaps;
};

addPlayedMaps("Stage1");
addPlayedMaps("Stage1");
addPlayedMaps("Stage1");
addPlayedMaps("Stage1");
addPlayedMaps("Stage1");
console.log(playedMaps["Stage1"].sort());



Então eu executo a função 5 vezes, para que todos os valores de allMaps.Stage1 preencham o playedMaps.Stage1.

addPlayedMaps("Stage1");
addPlayedMaps("Stage1");
addPlayedMaps("Stage1");
addPlayedMaps("Stage1");
addPlayedMaps("Stage1");
console.log(playedMaps["Stage1"].sort());


Entretanto, nem sempre eu consigo adicionar 5 valores. As vezes o console log me dá 4 valores ou 3...
O que tem de errado no meu loop for() ?

for(let i = getRandomInt(5, 9); // i é igual a qualquer um dos números: 5, 6, 7, 8, 9.
playedMaps[stage].indexOf(i) === -1; // Se i não existir no objeto(se o index dele for -1) playedMaps[stage], então executa a declaração.
i = getRandomInt(5, 9) ){ // Caso i já exista no objeto, fazer o sorteio de novo entre os números 5 a 9.
playedMaps[stage].push(i); // Declaração sendo executada e adicionando i ao objeto.
}
Eliaquim Nascimento

Eliaquim Nascimento

Responder

Post mais votado

12/03/2020

O seu problema está no loop. Seu loop foi criado da maneira errada, pois você está reatribuindo sua variável "i" no fim do statement.
Um outro problema da sua função é que ela pega um intervalo de números ( motivo pelo qual eu recomendo usar um array de strings de primeira pra facilitar o entendimento )

Quando você faz getRandomInt(5, 9), isso se resolve pro Stage1, mas não resolve para o stage2, que vai de 11 a 15, obrigando você a escrever dois loops diferentes, não possibilitando você reutilizar sua função para outros stages.
Outro problema do seu loop é que ele não leva em consideração todos os estágios de allMaps, causando uma coincidência de valores.

Abaixo eu te proponho uma funcao que você pode reutilizar para qualquer stage.

Ela vai adiciona um único mapa no array toda vez que ela for chamada e vai validar se o array já está cheio também.

Dá uma olhadinha

function addPlayedMaps (stage) {
    const allMapsLenght = (allMaps[stage].length - 1)
    const randomInt = getRandomInt(0, allMapsLenght)

    if (playedMaps[stage].length >= allMaps[stage].length) {
        return
    }
    
    const hasPlayed = playedMaps[stage].some(mapItem => {
        if (mapItem === allMaps[stage][randomInt]) {
            return true
        }
    })

    if (!hasPlayed && !!allMaps[stage][randomInt]) {
        playedMaps[stage].push(allMaps[stage][randomInt])
    }
     
    if (hasPlayed) {
        addPlayedMaps(stage)
    }
}

Stella Oliveira

Stella Oliveira
Responder

Mais Posts

12/03/2020

Eliaquim Nascimento

Seu loop foi criado da maneira errada, pois você está reatribuindo sua variável "i" no fim do statement.

Hmm... Não imaginaria que fosse isso... achei que reatribuir o valor ali, funcionasse como i++ ou i--, que no meu caso seria gerar um outro valor aleatório de 5 a 9.
Nesse caso, eu poderia gerar esse valor novamente no loop, dentro do corpo(declaração)?

for(let i = getRandomInt(5, 9); playedMaps[stage].indexOf(i) === -1; ){
    playedMaps[stage].push(i);
i = getRandomInt(5, 9) // Aqui?
}


Um outro problema da sua função é que ela pega um intervalo de números ( motivo pelo qual eu recomendo usar um array de strings de primeira pra facilitar o entendimento )

Array de strings de primeira?
Tipo assim:
ler arr = [ ["5","6","7","8","9"], ["11","12","13","14","15"] ... ]

Quando você faz getRandomInt(5, 9), isso se resolve pro Stage1, mas não resolve para o stage2, que vai de 11 a 15, obrigando você a escrever dois loops diferentes, não possibilitando você reutilizar sua função para outros stages.

Sim, verdade! É que eu tava querendo primeiro fazer funcionar hahaha

Eu testei a função e funcionou direitinho!!! Ficou fera, obrigadão mesmo!


if (!hasPlayed && !!allMaps[stage][randomInt]) {
playedMaps[stage].push(allMaps[stage][randomInt])
}

Usar o "randomInt aqui > allMaps[stage][randomInt] < foi um mindblowing pra mim xD
Valeu mesmo.

Eu só não entendi essa condição: "!!allMaps[stage][randomInt]", dois pontos de exclamação? Duas negativas? Para que serve esses dois?



Responder

13/03/2020

Stella Oliveira

Isso serve apenas pra forçar um true/false.
No javascript:

//Se você fizer
const obj = {
  foo: "bar"
}

if (obj.foo) // isso é true por que o JS avalia ele como um objeto que existe

if (!obj.foo) // isso é false por que o javascript converte para booleano
if (!!obj.foo) // eu estou convertendo para um booleano e invertendo o valor dele !obj.foo == false, !!obj.foo == true


É só pra garantir que vai funcionar

Entretanto, o seu código ainda tem um problema. Se um dos seus arrays contiver um número 0, ele vai dar errado. Por que em JS, o valor 0 é tratado como false. Sei que sua questão tem a ver com aprender, mas vale atentar que:

const allMaps = {
  Stage0: null,
  Stage1: [0, 5,6,7,8,9] // esse 0 vai automaticamente dar false 
}


Responder

13/03/2020

Eliaquim Nascimento

Haaa sim...
Entendi o lance do "!!".

Sim, eu fiquei ciente que o número 0 pode dar false, depois de entender a explicação.
Esses números são o ID de cada mapa, e os Id's são sempre maiores que 0, então não corro esse risco.
Muito obrigado pela ajuda, problema resolvido! ^^
Responder

14/03/2020

Stella Oliveira

Cara, agora que vi que não respondi outras perguntas suas:

Você citou

Array de strings de primeira?
Tipo assim:
ler arr = [ ["5","6","7","8","9"], ["11","12","13","14","15"] ... ]


Eu queria dizer strings mesmo. Acho que nesse ponto você já sabe, mas vale lembrar que o JS é uma linguagem que força tipagem

if (5 == "5") // isso é true


Então usar números em comparações exatas sempre é meio perigoso. Eu, particularmente, usaria assim ( já aviso que entendo o problema de dar nomes assim, uma hora a criatividade acaba haha ):

let arr = ["dust2", "poolday"] // e por ai vai


Mas eu digo isso mais pelo contexto. Na hora de programar, é mais fácil eu pensar que eu to comparando a "dust2" dos que já joguei com a "dust2" de allMaps. Eu falei isso mais por facilitar seu entendimento do seu código, mas depois que você me disse que recebe um array de ids, eu meio que entendi qual foi a intenção :)

Você também mencionou
Nesse caso, eu poderia gerar esse valor novamente no loop, dentro do corpo(declaração)?


Você até poderia fazer o que você propôs ( não sei dizer se daria certo por que eu mesmo não testei ), mas eu te colocaria o seguinte argumento:
Escrever o código daquela maneira não é muito comum, portanto deixa seu código mais difícil de entender pra um futuro colega e até mesmo pra você daqui um tempo. Eu, inclusive, te faço uma proposta: volta nessa questão que você abriu daqui 3 meses e dá uma lida nela. Eu te garanto que vai ser meio difícil de você entender o código que você propôs, por que nele falta clareza de intenção. Algo que é bastante discutido no livro Clean Code do Martin Fowler ( super recomendo, inclusive )

:D
Responder

14/03/2020

Stella Oliveira

Leituras adicionais que eu mesmo li e recomendo sempre que posso

- https://www.amazon.com.br/C%C3%B3digo-limpo-Robert-C-Martin/dp/8576082675/ref=asc_df_8576082675/?tag=googleshopp00-20&linkCode=df0&hvadid=379792215563&hvpos=&hvnetw=g&hvrand=4226168958323978339&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1001566&hvtargid=pla-398225630878&psc=1

- https://martinfowler.com/ieeeSoftware/explicit.pdf

- https://medium.com/@kennethreilly/coding-with-intention-d1d61f5add20

- https://novatec.com.br/livros/programador-melhor/
Responder

14/03/2020

Eliaquim Nascimento

Opa!!
Valeu por responder as outras questões!
Eu ia perguntar de novo, mas acabei entendendo depois que mexi na função de novo aqui.

Vou ficar de olho nesses livros, de repente algum deles tem no KindleUnlimited. Obrigado mesmo pelas recomendações, eu acho tantos livros que as vezes não sei qual vale a pena ler devido ao meu tempo. Então sempre bom ter umas recomendações.

Eu, inclusive, te faço uma proposta: volta nessa questão que você abriu daqui 3 meses e dá uma lida nela. Eu te garanto que vai ser meio difícil de você entender o código

acontece a todo momento hahaha
Responder

Assista grátis a nossa aula inaugural

Assitir aula

Saiba por que programar é uma questão de
sobrevivência e como aprender sem riscos

Assistir agora

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar