How to play items with a specific value for the beginning of an array?

Asked

Viewed 144 times

4

I have an array questions[] with the following properties:

perguntas[0] = { id:1; ordem: 3; inicio: 1 };
perguntas[1] = { id:2; ordem: 2; inicio: 0 }; 
perguntas[2] = { id:3; ordem: 1; inicio: 1 };

I would like to exchange them order in the array according to the start property. Where 1 must come before 0.

I already use a function to sort according to the order property, only that this sort would be secondary, giving priority to items with the start property marked as 1.

How can I do that?

The expected result would be:

perguntas[0] = { id:3; ordem: 1; inicio: 1 };
perguntas[1] = { id:1; ordem: 3; inicio: 1 }; 
perguntas[2] = { id:2; ordem: 2; inicio: 0 };
  • Is this the order you expect, or is it 3/1/2? Or is it 3/1 or 1/3?

  • @bfavaretto When the AP speaks of "order according to property order", I assume it is in ascending order, in the absence of any indication to the contrary. The expected result would therefore be correct.

  • 1

    That may be, but I was confused by what is said in the first half of the question. I don’t know if the array given there has passed the current sort function or not. @mgibsonbr

3 answers

5

We already have good answers, but follows a version that sorts by several columns, using the .sort traditional, if someone needs in the future:

var perguntas = [];
perguntas[0] = { id:1, ordem: 3, inicio: 1 };
perguntas[1] = { id:2, ordem: 2, inicio: 0 }; 
perguntas[2] = { id:3, ordem: 1, inicio: 1 };
perguntas[4] = { id:3, ordem: 4, inicio: 1 };
perguntas[3] = { id:1, ordem: 4, inicio: 1 };
perguntas[5] = { id:3, ordem: 5, inicio: 1 };

// Aumente o "peso" a cada coluna extra
// sinal( ) * 8, * 16, * 32 etc...
var resultado = perguntas.sort(function (a, b) { return (
  sinal( a.inicio - b.inicio ) * 4 +
  sinal( a.ordem  - b.ordem  ) * 2 +
  sinal( a.id     - b.id     )
); } );

// Math.sign não é suportado em todos os browsers, segue implementação local:
function sinal( i ) {
  return ( i > 0 ) - ( i < 0 );
}

// Essa parte aqui é só pra exibir o resultado para conferirmos:
for ( i = 0; i < resultado.length; i++ ) {
  document.body.innerHTML += '<p>' + JSON.stringify( resultado[i] ) + '</p>';
}

In this case, it is enough to put "weights" on the desired items, so that it weighs more the difference of the main column, but if it draws, it weighs more the second column, and so on.

Therefore, we use power of 2 in the weights ( 1, 2, 4, 8, 16 ), to ensure that the weights of the lower columns together never exceed a higher column.

3


You can do it like this, by following the indications from the MDN:

var ordenada = perguntas.sort(function (a, b) {
    if (a.inicio > b.inicio) return -1;
    if (a.inicio < b.inicio) return 1;
    return 0;
});

Example:

var perguntas = [];
perguntas[0] = {
    id: 1,
    ordem: 3,
    inicio: 1
};
perguntas[1] = {
    id: 2,
    ordem: 2,
    inicio: 0
};
perguntas[2] = {
    id: 3,
    ordem: 1,
    inicio: 1
};

var ordenada = perguntas.sort(function (a, b) {
    if (a.inicio > b.inicio) return -1;
    if (a.inicio < b.inicio) return 1;
    return 0;
});

alert(JSON.stringify(ordenada, null, 2));

Notice that you have a syntax error in the objects: it must be , to separate the properties and not ;

  • 1

    Note that the standard implementation of sort is not necessarily stable. Depending on the environment in which this code is executed, the sort by inicio can totally invalidate the initial ordering by ordem. In this case, the relative order of the elements with the same inicio is undefined.

  • @mgibsonbr I saw your answer (and "upei") but from the list of browsers that the answer you indicated in the current browsers it doesn’t seem problem anymore.

  • Indeed, but as the AP decided to mark this answer as accepted, I thought it important to leave this warning here, for those who come to this question in the future. After all, if you’re not in standard, cannot be trusted blindly... :)

  • @mgibsonbr well seen.

3

You can create a new sorting function that makes use of the first:

perguntas = perguntas.sort(function(a, b) {
    return a.inicio > b.inicio ? -1 : b.inicio > a.inicio ? 1 : comparadorAntigo(a, b);
});

Or, if you have access to an implementation stable (it seems to me that the sort Javascript standard does not impose this restriction, so that different browsers implement this inconsistently) you can sort first by the secondary feature, then by the primary. Example using underscore.js:

var perguntas = [];
perguntas[0] = { id:1, ordem: 3, inicio: 1 };
perguntas[1] = { id:2, ordem: 2, inicio: 0 }; 
perguntas[2] = { id:3, ordem: 1, inicio: 1 };

perguntas = _.sortBy(perguntas, "ordem"); // Ou seja qual for seu critério secundário
perguntas = _.sortBy(perguntas, function(x) { return -x.inicio; });

document.getElementsByTagName("body")[0].innerHTML = JSON.stringify(perguntas);
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>

Browser other questions tagged

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