How to make a Sort of a converted Nodelist to array?

Asked

Viewed 40 times

4

I am trying to sort the array by the style property order.

This is my attempt:

var interval = setInterval(() => {
  var letterDivs = gameBox.getElementsByClassName("wordBox")[0].childNodes;

  console.log([...letterDivs]);

  [...letterDivs].sort((a, b) => {
    (a.style.order > b.style.order) ? 1 : -1;
  });
  console.log(letterDivs);
}, 300);

The last console.log does not return the sorted list. Why? How do I sort the list?

  • (a.style.order > b.style.order) ? 1 : -1; => return (a.style.order > b.style.order) ? 1 : -1;?

  • 1

    I will not put that remark in my answer because it goes a little outside the scope of the question, but I would rethink the need to do the Sort from the list every 300 milliseconds. Array sorting operation are relatively costly for lists with many elements (large-O complexity O(n log n)), so make sure there’s no way to do this kind of thing out of of setInterval. :)

1 answer

3


The estate <elm>.style.order returns a string with the value set in the CSS property order of the element in question.

Since it is a string, you should worry about converting it to the appropriate type (number) since the comparison operators (such as >) compare strings lexicographically (so for example, '11' < '100' would return false, what is absurd from the numerical point of view).

That said, you can do something like this:

const letterDivs = document.querySelectorAll('.wordBox > *');

const sorted = [...letterDivs].sort((a, b) => {
  const aNum = parseInt(a.style.order, 10);
  const bNum = parseInt(b.style.order, 10);
  
  // Irá jogar aqueles com `order` inválido para o final.
  if (Number.isNaN(aNum)) return 1;
  if (Number.isNaN(bNum)) return -1;
  
  // Ordena de ordem crescente:
  return aNum - bNum;
});

console.log(sorted.map((el) => el.textContent));
<div class="wordBox">
  <span style="order: 4">4</span>
  <span style="order: 2">2</span>
  <span>Sem Order</span>
  <span style="order: 3">3</span>
  <span style="order: 1">1</span>
  <span style="order: dasdkaj">Order Inválido</span>
  <span style="order: 5">5</span>
</div>

Note that I used map at the end of the previous example only to print the text of each element in the console. But this shows that the list was correctly ordered.

Note that I have also been concerned with dealing with possible cases where the element does not have a property order valid. In this case, either a string or an empty string would be returned. How Javascript interprets them as NaN by means of parseInt, check if they are NaN and order them within the comparison function. In this case, I sort them to the end of the list.

And the expression [...letterDivs].sort((a, b) => /* ... */) returns a new array. How we use the Operator spread within a new literal array, the NodeList letterDivs original will not be modified, since it was only used to make a copy for a new array. Thus, we need to assign the result of the expression in question to a new variable. In this case, I created a new variable called sorted.

And finally its comparison function was also not returning any value. I used the return for that reason. Learn more.

  • It worked! But I didn’t realize how the difference between aNum and bNum sort the Orders by odem ascending.

  • 1

    @Inêsbaratafeioborges, the function of the sort receives two parameters (a and b). If you return a number less than 1, put a in an index prior to b. If it returns 0, it does not change. And if it returns a number greater than 1, it puts a in index after b. So the difference does just that (assuming they are numbers). When we subtract b of a (a - b), we say that if b is greater than a, we will have a negative result, so that a will go to before of b. On the other hand, if b is less than a, results in a positive number in which a shall be moved to after b.

  • 1

    It works if you want to sort down too, but then you have to do it b - a. :)

Browser other questions tagged

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