2010-07-21 18 views
13

Supposons que j'ai une liste de choses (nombres, de garder les choses simples ici) et j'ai une fonction que je veux utiliser pour les trier par, en utilisant SortBy. Par exemple, le suivant trie une liste de numéros par le dernier chiffre:tri stable, à savoir, minimalement Disruptive tri

SortBy[{301, 201}, Mod[#,10]&] 

Et remarquez comment deux (c.-à-tous) ces chiffres ont le même chiffre. L'ordre dans lequel nous les renvoyons n'a pas d'importance. Dans ce cas, Mathematica les renvoie dans l'ordre inverse. Comment puis-je m'assurer que tous les liens sont rompus en faveur de la façon dont les articles ont été commandés dans la liste originale?

(Je sais que c'est un peu trivial mais j'ai l'impression que cela arrive de temps en temps, alors j'ai pensé que ce serait pratique pour l'obtenir sur StackOverflow. me bat à elle)

Les tentatives de faire de ce plus des recherches. genre avec une perturbation minimale, sorte avec moins nombre de swaps, bRIS sur mesure, le tri avec swapping coûteux, stable de tri.

PS: Merci à Nicholas de remarquer que ce qu'on appelle le tri stable. C'était sur le bout de ma langue! Voici un autre lien: http://planetmath.org/encyclopedia/StableSortingAlgorithm.html

+2

Est-ce que la chose recherchée ici n'est pas simplement un algorithme de tri stable? Voir: http://en.wikipedia.org/wiki/Sorting_algorithm#Stability –

Répondre

16

Après avoir demandé autour, on m'a donné une explication satisfaisante:

Réponse courte: Vous voulez SortBy[list, {f}] obtenir une sorte stable.

Réponse longue:

SortBy[list, f] liste des sortes dans l'ordre déterminé par l'application f à chaque élément de la liste, ex aequo en utilisant l'ordre canonique expliqué dans Trier. (Ceci est la deuxième note "Plus d'informations" documentée dans le documentation for SortBy.

SortBy[list, {f, g}] casse les attaches en utilisant l'ordre déterminé en appliquant g à chaque élément.

Notez que SortBy[list, f] est la même que SortBy[list, {f, Identity}].

SortBy[list, {f}] ne fait pas bris d'égalité (et donne une sorte stable), ce qui est ce que vous voulez:

In[13]:= SortBy[{19, 301, 201, 502, 501, 101, 300}, {Mod[#, 10] &}] 

Out[13]= {300, 301, 201, 501, 101, 502, 19} 

Enfin, la solution de Sakra SortBy[list, {f, tie++ &}] est effectivement équivalent à SortBy[list, {f}].

+0

Wow, merci, Andrew! J'ai lu ceci et je me suis dit "tu viens de demander où tu travailles, Wolfram Research?" Puis j'ai cliqué sur ton nom et j'ai vu que tu le faisais. :) Je suis toujours étonné des niveaux d'expertise que StackOverflow attire. Merci beaucoup d'être ici! – dreeves

2

Cela semble fonctionner:

stableSortBy[list_, f_] := 
    SortBy[MapIndexed[List, list], {[email protected][#], Last[#]}&][[All,1]] 

Mais maintenant je vois rosettacode donne une beaucoup plus agréable façon de le faire:

stableSortBy[list_, f_] := list[[Ordering[f /@ list]]] 

Alors commande est la clé! Il semble que la documentation de Mathematica ne mentionne pas cette différence parfois importante. Trier et commander.

+1

Cette approche est appelée l'idiome "decorate-sort-undecorate" dans les cercles Lisp, et même si 'GatherBy' peut être la meilleure approche pour un tri stable dans en particulier, c'est un tour phénoménalement utile dans Mathematica. – Pillsy

+1

Je serais curieux de savoir comment cela se compare à 'GatherBy' en termes de vitesse, et cela dépend de la façon dont les listes sont implémentées en interne. Mon problème est que 'GatherBy' pourrait seulement toucher chaque élément de la liste une fois, tandis que la solution' Ordering' nécessiterait au moins deux fois: une fois pour le tri et une fois pour la réorganisation des éléments. Pour les petites listes, cela n'a pas d'importance. Mais, sans le faire réellement, je suspecte que pour les listes plus longues, 'GatherBy' donnera des performances supérieures. – rcollyer

+0

PS: Je pense que tout cela est discutable à la lumière de la réponse acceptée. – dreeves

6

Est-ce que GatherBy fait ce que vous voulez?

Flatten[GatherBy[{301, 201, 502, 501, 101}, Mod[#, 10] &]] 
+1

Oh, c'est probablement le cas, merci! Je n'avais pas pensé à utiliser GatherBy. Je suis enclin à aller avec la solution de commande. Si vous êtes curieux et que vous voulez comparer les solutions à ce jour avec des tests de timing, je vais faire de votre réponse la réponse acceptée. (Oh, un problème avec votre solution: vous devriez faire Flatten [..., 1] sinon si les éléments étaient en réalité des listes alors le Flatten les ruinerait.) – dreeves

+0

PS: Je pense que ceci est maintenant discutable à la lumière de la réponse acceptée . – dreeves

4

Il existe une variante de SortBy qui rompt les liens en utilisant des fonctions de commande supplémentaires:

SortBy[list,{f1, f2, ...}]

par des liens de comptage, vous pouvez ainsi obtenir un tri stable:

Module[{tie = 0}, 
SortBy[{19, 301, 201, 502, 501, 101, 300}, {Mod[#, 10] &, (tie++) &}]] 

rendements

{300, 301, 201, 501, 101, 502, 19} 
+0

Merci, je ne le savais pas! Il s'avère que c'est encore plus simple, comme le montre la réponse acceptée. – dreeves