web-dev-qa-db-fra.com

Fonction de tri Javascript. Trier par d'abord puis par seconde

J'ai un tableau d'objets à trier. Chaque objet a deux paramètres: Force et Nom.

objects = []
object[0] = {strength: 3, name: "Leo"}
object[1] = {strength: 3, name: "Mike"}

Je veux trier d'abord par force, puis par nom alphabétiquement. J'utilise le code suivant pour trier par le premier paramètre. Comment puis-je trier alors à la seconde? 

function sortF(ob1,ob2) {
  if (ob1.strength > ob2.strength) {return 1}
  else if (ob1.strength < ob2.strength){return -1}
  return 0;
};

Merci de votre aide. 

45
Leonardo Amigoni

Développez votre fonction de tri pour être comme ça;

function sortF(ob1,ob2) {
    if (ob1.strength > ob2.strength) {
        return 1;
    } else if (ob1.strength < ob2.strength) { 
        return -1;
    }

    // Else go to the 2nd item
    if (ob1.name < ob2.name) { 
        return -1;
    } else if (ob1.name > ob2.name) {
        return 1
    } else { // nothing to split them
        return 0;
    }
}

Une comparaison < et > sur des chaînes est une comparaison alphabétique.

67
Matt

Cette petite fonction est souvent utile pour trier plusieurs clés: 

cmp = function(a, b) {
    if (a > b) return +1;
    if (a < b) return -1;
    return 0;
}

ou, plus concis,

cmp = (a, b) => a > b - a < b

Appliquez-le comme ceci:

array.sort(function(a, b) { 
    return cmp(a.strength,b.strength) || cmp(a.name,b.name)
})

Il manque vraiment Javascript à l'opérateur Ruby - du vaisseau spatial , ce qui rend ces comparaisons extrêmement élégantes. 

40
georg

Vous pouvez chaîner l'ordre de tri avec un OU logique.

objects.sort(function (a, b) {
    return a.strength - b.strength || a.name.localeCompare(b.name);
});
20
Nina Scholz

Lorsque je cherchais une réponse à cette question, les réponses que j'ai trouvées sur StackOverflow n'étaient pas vraiment celles que j'espérais. J'ai donc créé une fonction simple et réutilisable qui fait exactement cela. Cela vous permet d'utiliser le standard Array.sort, mais avec le style firstBy (). ThenBy (). ThenBy () . https://github.com/Teun/thenBy.js

PS. C'est la deuxième fois que je poste ceci. La première fois a été supprimée par un modérateur: "Ne faites pas de messages promotionnels pour votre propre travail". Je ne suis pas sûr de savoir quelles sont les règles ici, mais j'essayais de répondre à cette question. Je suis vraiment désolé que ce soit mon propre travail. N'hésitez pas à supprimer à nouveau, mais s'il vous plaît dirigez-moi à la règle en cause alors.

5
Teun D
function sortF(ob1,ob2) {
  if (ob1.strength > ob2.strength) {return 1}
  else if (ob1.strength < ob2.strength) {return -1}
  else if (ob1.name > ob2.name) {return 1}
  return -1;
};

EDIT: Triez par force, puis si force est égale, triez par nom . Le cas où force et nom sont égaux dans les deux objets n'a pas besoin d'être pris en compte séparément relation -à-ou-égale-à. Le résultat du tri sera correct. Cela pourrait accélérer ou ralentir, je ne sais pas. Si vous voulez être explicite, remplacez simplement

return -1;

avec

else if (ob1.name < ob2.name) {return -1}
return 0;
0
steve

la réponse de steve, mais plus jolie.

objects.sort(function(a,b)
{
  if(a.strength > b.strength) {return  1;}
  if(a.strength < b.strength) {return -1;}
  if(a.name     > b.name    ) {return  1;}
  if(a.name     < b.name    ) {return -1;}
  return 0;
}
0
rocketsarefast

Trouvez la fonction 'sortFn' ci-dessous. Cette fonction trie par nombre illimité de paramètres (comme dans c #: SortBy (...). ThenBy (...). ThenByDesc (...)).

function sortFn() {
    var sortByProps = Array.prototype.slice.call(arguments),
        cmpFn = function(left, right, sortOrder) {
            var sortMultiplier = sortOrder === "asc" ? 1 : -1;

            if (left > right) {
                return +1 * sortMultiplier;
            }
            if (left < right) {
                return -1 * sortMultiplier;
            }
            return 0;
        };


    return function(sortLeft, sortRight) {
        // get value from object by complex key
        var getValueByStr = function(obj, path) {
            var i, len;

            //prepare keys
            path = path.replace('[', '.');
            path = path.replace(']', '');
            path = path.split('.');

            len = path.length;

            for (i = 0; i < len; i++) {
                if (!obj || typeof obj !== 'object') {
                    return obj;
                }
                obj = obj[path[i]];
            }

            return obj;
        };

        return sortByProps.map(function(property) {
            return cmpFn(getValueByStr(sortLeft, property.prop), getValueByStr(sortRight, property.prop), property.sortOrder);
        }).reduceRight(function(left, right) {
            return right || left;
        });
    };
}

var arr = [{
    name: 'marry',
    LocalizedData: {
        'en-US': {
            Value: 10000
        }
    }
}, {
    name: 'larry',
    LocalizedData: {
        'en-US': {
            Value: 2
        }
    }
}, {
    name: 'marry',
    LocalizedData: {
        'en-US': {
            Value: 100
        }
    }
}, {
    name: 'larry',
    LocalizedData: {
        'en-US': {
            Value: 1
        }
    }
}];
document.getElementsByTagName('pre')[0].innerText = JSON.stringify(arr)

arr.sort(sortFn({
    prop: "name",
    sortOrder: "asc"
}, {
    prop: "LocalizedData[en-US].Value",
    sortOrder: "desc"
}));

document.getElementsByTagName('pre')[1].innerText = JSON.stringify(arr)
pre {
    font-family: "Courier New" Courier monospace;
    white-space: pre-wrap;
}
Before:
<pre></pre>
Result:
<pre></pre>

0
Igor Shubin

Que diriez-vous d'un inliner long et puissant:

const orderByMultipleFactory = (fields) => (a, b) => fields.reduce((acc, {name, asc = true, compareFn}) => acc || (compareFn ? compareFn(a, b) : (isString(a[name]) ? (asc ? a[name].localeCompare(b[name]) : b[name].localeCompare(a[name])) : (asc ? a[name] - b[name] : b[name] - a[name]))), 0);

Fields est un tableau d'objets avec le champ name qui spécifie la propriété de object, puis les options facultatives asc et compareFn pour contrôler la direction ou remplacer la méthode de comparaison par défaut.
Par défaut, les chaînes sont comparées par localCompare et le reste par simple a - b.

Exemple:

[{a: 2, b: 'y'}, {a: 3, b: 'x'}, {a: 2, b: 'z'}]
  .sort(orderByMultipleFactory([{name: 'a', asc: false}, {name: 'b'}]))
// result is sorted by "a" descending and equal records by "b" ascending.
0
icl7126

En 2018, vous pouvez utiliser simplement la fonction sort () ES6, qui fait exactement ce que vous voulez https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array /Trier

0
Kamil Naja

Avec ES6, vous pouvez faire 

array.sort(function(a, b) { 
 return SortFn(a.strength,b.strength) || SortFn(a.name,b.name)
})

 private sortFn(a, b): number {
    return a === b ? 0 : a < b ? -1 : 1;
}
0
Josf