How to get an index() of an array with the same element multiple times?

Asked

Viewed 208 times

0

inserir a descrição da imagem aqui

The idea is to sort the letters to write an HTML5 element in this case the "tfoot". But when I change the second letter t by the does not change me right. I know why. is because the index I picked up corresponds to the first element with that innerHTML, in this case the index of t will be the first t which is wrong. Here is the javascript mycode.

word = gameMechanics[1];
  let lettertoSwitch = 0; // To be in the scope of the function
  let letterToBeSwitchedWith = 0;
  let indexLettertoSwitch = 0;
  letters.forEach((letter) => {
    letter.addEventListener("click", (e) => {
      if(turn % 2 === 0){ // If its the first time the user clicks on the letter
        lettertoSwitch = letter.style.order; // Stores the position of the letter
        indexLettertoSwitch = word.indexOf(letter.innerHTML); // Stores the index of the letter
        turn ++;
      }else if(turn % 2 === 1){ // If its the second time the user clicks on a letter
        letterToBeSwitchedWith = letter.style.order; // Stores the position of the letter
        turn ++;
        
      }
      if(turn % 2 == 0 && turn !== 0){ // If the player has made to moves and its not the first turn
        letter.style.order = lettertoSwitch; // Switches the current letter with the first one clicked
        letters[indexLettertoSwitch].style.order = letterToBeSwitchedWith; // Switches the second clicked letter with first one clicked
        console.log(lettertoSwitch, letterToBeSwitchedWith);
      }
    })

How can I get the index of the letter through the order property of the element, as it is the only unique property that can distinguish the same letters? You could use the event to access the element index?

4 answers

4


I believe that the IndexOf() will not solve your problem.

I’d go for something simpler

1) Position each character in a tag with a specific id

<span id="0" onClick="reply_click(this.id)">t</span>
<span id="1" onClick="reply_click(this.id)">o</span>
<span id="2" onClick="reply_click(this.id)">o</span>
<span id="3" onClick="reply_click(this.id)">t</span>
<span id="4" onClick="reply_click(this.id)">f</span>

2) Clicking on the character returns the id of it, which would already be the position.

function reply_click(clicked_id)
  {
      alert(clicked_id);
  }

Note Of course you will not alert, but change the character

See this code here:

function reply_click(clicked_id)
  {
      alert(clicked_id);
  }
<span id="0" onClick="reply_click(this.id)">t</span>
<span id="1" onClick="reply_click(this.id)">o</span>
<span id="2" onClick="reply_click(this.id)">o</span>
<span id="3" onClick="reply_click(this.id)">t</span>
<span id="4" onClick="reply_click(this.id)">f</span>

I hope it helps.

  • It worked! Good logic. Interesting that there is no function to get the index by the style property.

2

It all depends on how you structure your HTML code. One way is to define each letter in an independent element so that it can record events in each letter and execute logic to exchange the letters.

The following code is based on this structure and uses javascript for:

  • Generate HTML, given a word;
  • Record events for each letter;
  • Run logic for changing letters;
  • Check if the word matches the initial (correct).

I ended up getting excited about implementing this. I hope it helps.

// Check if a given word is valid for the purpose of this example.
// A word is considered valid if it has at least 2 letters and not all the letters are the equals.
const isValidWord = (word) => {
  if (word.length < 2) return false;
  
  const wordArray = [...word];
  
  return wordArray.filter(
    (letter) => wordArray[0] === letter,
  ).length !== wordArray.length;
};

// Randomly shuffle letters in a given word and return it.
// It makes sure the shuffled word is not equals to the given word.
const shuffleWord = (word) => {
  const wordArray = [...word];
  const shuffledWord = wordArray.sort(() => Math.random() - .5).join('');
  
  return shuffledWord !== word ? shuffledWord : shuffleWord(word);
};

// Generate and return and HTML element representing a word.
// Example: <div class="word"><span class="letter">A</span></div>
const generateWordElement = (word) => {
  const wordElement = document.createElement('div');
  
  wordElement.classList.add('word');
  [...word].forEach(
    (letter) => wordElement.appendChild(generateLetterElement(letter)),
  );
  
  return wordElement;
};

// Generate and return and HTML element repsenting a letter.
// Example: <span class="letter">A</span>
const generateLetterElement = (letter) => {
  const letterElement = document.createElement('span');
  
  letterElement.classList.add('letter');
  letterElement.appendChild(document.createTextNode(letter.toUpperCase()));
  
  return letterElement;
};

// Register a click event listener for every letter element.
// It calls switchLetter passing the letter element clicked as argument
// and then checks if the word is right by calling wordMatch.
const registerEventListeners = (word) => {
    document.querySelectorAll('.word .letter').forEach((letterElement) => {
    letterElement.addEventListener(
      'click',
      (event) => {
        switchLetter(event.target);
        wordMatch(word);
      },
    );
  });
};

// Try to switch letters between 2 clicked elements.
// It uses a global swap variable to store the 1st clicked element.
// When there's already a clicked element, it switch them and set the swap element back to null.
const switchLetter = (clickedLetterElement) => {
  if (!swapLetterElement) {
    swapLetterElement = clickedLetterElement;
    swapLetterElement.classList.add('letter--selected');

    return;
  }

  const swapLetter = swapLetterElement.textContent;
  swapLetterElement.textContent = clickedLetterElement.textContent;
  clickedLetterElement.textContent = swapLetter;
  swapLetterElement.classList.remove('letter--selected');
  swapLetterElement = null;
};

// Check if the current word element matches the initial word.
const wordMatch = (word) => {
  const currentWord = Object.values(document.querySelectorAll('.word .letter')).map(
    (letterElement) => letterElement.textContent,
  ).join('');

  if (currentWord === word.toUpperCase()) {
    document.querySelector('.word').classList.add('word--match');
  }
};

// Initialize the game
const init = (word) => {
  if (!isValidWord(word)) return;

  document.querySelector('body').appendChild(
    generateWordElement(shuffleWord(word))
  );

  registerEventListeners(word);
};

let swapLetterElement = null;
init('tfoot');
@import url('https://fonts.googleapis.com/css2?family=Play&display=swap');

.word {
  display: flex;
  justify-content: center;
  padding: 15px;
  font-family: 'Play', sans-serif;
  font-size: 30px;
}

.word.word--match {
  background-color: mediumspringgreen;
  pointer-events: none;
}

.word.word--match .letter {
  border-color: teal;
  color: teal;
}

.letter {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  margin: 5px;
  border: 3px solid darkgray;
  border-radius: 5px;
  background-color: lightgray;
  height: 50px;
  width: 50px;
  cursor: pointer;
  transition: all ease .25s;
}

.letter.letter--selected {
  border-color: teal;
  color: teal;
  background-color: white;
}

1

Algorithm

If I understand correctly, you just need to of the index of the clicked letter. I imagine you need an algorithm following the logic of the function below:

function getIndexOfNthLetter(array, nPositionInArray, letter) {
    // declarando as variáveis que serão usadas
    let currentLetter, position = 1;

    for (let i = 0; i < array.length; i++) {
        // resgatando letra atual
        currentLetter = array[i];

        /* 
         *  caso a letra seja a mesma que deseja E a posição no array também, retorne
         *  a partir do índice atual, para não retornar o índice de uma letra passada
        */
        if (letter === currentLetter && position === nPositionInArray) {
            return array.indexOf(currentLetter, i);
        } else if (currentLetter === letter) {
            // caso contrário, a posição não é a desejada mas continuamos seguindo...
            position++;
        }
    }

    // retornando -1 caso nenhuma letra tenha sido encontrada no índice indicado
    return -1;
}

The use of the above function would be:

getIndexOfNthLetter(array, 2, "t"); // Solicitando o segundo "t", índice: 3
getIndexOfNthLetter(array, 2, "r"); // Solicitando o segundo "r" (que não existe no array), índice: -1

Completion and use of indexOf

Your use of the function indexOf should contain two arguments: The letter and from where to look, ie in the index of the current letter, so that the index of the first "t" does not return, as in your use case.

If you search for the "t" from the second "t", you will have its index, because the array would only be considered from there.

I hope I’ve helped in some way.

0

save the index of the first occurrence and use the index as offset for the next query "recursively":

var indexOcorrencias = [];
var text = 'tootf';
var toSearch = 't';
var index = text.indexOf(toSearch);
while (index>=0) {
  indexOcorrencias.push(index);
  index += toSearch.length;
  index = text.indexOf(toSearch, index);
}
//indexOcorrencias = [0,3];

index function:

indexOf(find[,offset])
  • I didn’t realize how this will give me the index of the clicked letter?! gives me an array of Indexes not the index of the clicked letter

  • it would be easier to understand if you had said this instead of "How to get an index() of an array with the same element multiple times?"

Browser other questions tagged

You are not signed in. Login or sign up in order to post.