7
votes

Liste de tri par des valeurs tuples imbriquées

Y a-t-il un meilleur moyen de trier une liste par une valeur de tuple imbriquée que d'écrire une alternative d'itemGetter qui extrait la valeur tuple imbriquée: xxx

J'ai pensé à utiliser composer, mais ce n'est pas dans La bibliothèque standard: xxx

existe quelque chose que j'ai manqué dans les libs qui rendrait ce code plus agréable?

La mise en œuvre doit fonctionner raisonnablement avec 100k articles.

Contexte: je voudrais trier un dictionnaire d'articles qui sont un histogramme. Les clés sont des tuples (A, B) et la valeur est le compte. À la fin, les éléments doivent être triés par compteur décroissant, A et B. Une alternative consiste à aplatir le tuple et à utiliser directement l'itemGetter, mais de cette manière beaucoup de tuples seront générées.


3 commentaires

Il n'y a pas à ce que je suis au courant. Votre approche est belle car elle est imho.


"La mise en œuvre devrait fonctionner raisonnablement avec 100 000 articles." - cette ligne est inutile; Toutes les implémentations utilisant trier fonctionneront raisonnablement avec 100k articles


@ninjagecko La mise en œuvre sera différente si vous triez 3 articles ou 100k ou 1T.


4 Réponses :


12
votes

Oui, vous pouvez simplement utiliser une clé = lambda x: x [0] [1]


8 commentaires

Est itemGetter (0) plus rapide que lambda x: x [0] ? Avoir composer (itemGetter (1), itemGetter (0)) , lambda x: x [0] [1] et profond_get la même performance caractéristiques?


La Lambda sera presque certainement plus rapide que toutes, mais tout est toujours o (n journal (n)) en raison du tri, donc je ne m'inquiéterais pas trop à ce sujet; Il y a probablement de meilleures choses à optimiser


Je pense que le poste d'article serait plus rapide que Lambda, car il est écrit en C. Pourquoi pensez-vous que Lambda est plus rapide?


@utdmr tout passe par C, mais vous allumez toujours en python; Vous ne pouvez vous attendre qu'à une vitesse si la majeure partie de votre calcul serait effectuée en C et si C a une sorte d'avantage majeur en évitant les frais généraux. En outre composer est implémenté avec un lambda (même chose qu'une fonction, vraiment) pour que vous n'économisez rien. Vous êtes invité à tester cela vous-même. Vous remplissez constatez que l'approche compose fonctionne de 50% plus lentement. Le Deep_Get Cependant, je m'attendrais à courir avec à peu près au même moment (en fait cela). Vous pouvez toujours utiliser dis.dis pour examiner ce que le code compile.


La déclaration " compose () est implémentée avec un lambda " est un peu étrange. Comment le sais-tu? Ma version de compose () peut être écrit comme une extension C ...


@Sven je vois que vous jouez à Devil's-avocat =) Si vous mettiez tout dans C, vous pourriez aussi bien écrire en C, et vous en supposer que vous écrivez toujours le programme en Python, vous avez toujours la "frais générale" d'interfaçage avec La convention d'appel Python dans C. Vous êtes invité à mettre en œuvre votre propre composer en tant que module C pour voir s'il est plus rapide; En fait, je serais curieux si cela aurait un effet. Néanmoins, je pense que les gens optimisent trop dans les mauvais endroits, que des décisions de conception expliquent davantage et que le temps de programmeur est plus précieux que les optimisations mineures.


@ninjagecko: Mon point était plutôt que vous ne savez simplement pas comment composer () est implémenté car il n'est pas une fonction standard. Habituellement, je l'installerais comme celui-ci , qui est sans lambda. Bien sûr, votre raisonnement serait toujours valable pour cette mise en œuvre. :)


@Sven Oui, c'est pourquoi j'ai dit "(même chose qu'une fonction, vraiment)" pour préempter cette discussion =) parce que types.funtType == types.Lambdatype def f ( x): retour x; dis.dis (f) et dis.dis (lambda x: x) donne les mêmes opcodes (aussi si vous les appelez avec * args, ** kw .



2
votes

Votre approche est assez bonne, compte tenu de la structure de données que vous avez.

Une autre approche serait d'utiliser une autre structure. p>

Si vous voulez une vitesse, la norme de facteur Numpy est la voie à suivre. Son travail consiste à gérer efficacement les grandes matrices. Il a même de belles routines de tri pour les tableaux comme le vôtre. Voici comment vous écririez votre tri sur les comptes, puis sur (A, B): P>

>>> arr = numpy.array([((2,1), 1),((1,3), 1),((3,6), 1),((4,5), 2)],
                  dtype=[('pos', [('a', int), ('b', int)]), ('count', int)])
>>> print numpy.sort(arr, order=['count', 'pos'])
[((1, 3), 1) ((2, 1), 1) ((3, 6), 1) ((4, 5), 2)]


0 commentaires

0
votes

J'ai comparé deux solutions similaires. Le premier utilise une simple lambda: xxx

notez le moins sur x [1] , car vous voulez que le tri soit décroissant sur le compte.

Le second tire le fait que trier dans Python est stable. Tout d'abord, nous trions par (a, b) (ascendant). Ensuite, nous trions par comptage, descendant: xxx

Le premier est de 10 à 20% plus rapide (à la fois sur de petits ensembles de données (à la fois sur de petits ensembles de données), et les deux complètes moins de 0,5 secondé sur mon Q6600 (un noyau utilisé) pour 100 000 articles. Donc, éviter la création de tuples ne semble pas aider beaucoup.


0 commentaires

1
votes

Cela pourrait être une version peu plus rapide de votre approche: xxx

qui pourrait être raccourci pour: xxx

ou même simplement simplement écrit: xxx


0 commentaires