2010-08-18 14 views
0

J'ai un tableau d'entiersComment imprimer un tableau d'entiers dans la console rapidement?

a = [1,2,3,4] 

Quand je

a.join 

Ruby appelle en interne la méthode to_s 4 fois, ce qui est trop lent pour mes besoins.

Quelle est la méthode la plus rapide pour afficher un grand nombre d'entiers sur la console?

Je veux dire:

a = [1,2,3,4........,1,2,3,9], should be: 

1234 ........ 1239

+0

Juste curieux: pourquoi avez-vous besoin d'en imprimer autant sur la console rapidement? –

Répondre

2

Comme indiqué dans les commentaires ci-dessus si Fixnum.to_s n'est pas effectuer rapidement assez pour vous alors vous devez vraiment considérer si Ruby est l'outil approprié pour cette tâche particulière.

Cependant, il y a plusieurs choses que vous pourriez faire qui pourraient ou non s'appliquer à votre situation.

Si la construction de la matrice se produit en dehors de la zone critique de temps, alors construisez la matrice, ou une copie de la matrice avec des chaînes au lieu d'entiers. Avec mon petit test de 10000 entiers, cela est environ 5 fois plus rapide.

Si vous contrôlez le processus de lecture et d'écriture, utilisez Array.pack pour écrire la sortie et String.unpack pour lire le résultat. Cela peut ne pas être plus rapide car le pack semble appeler Fixnum.to_int même si les éléments sont déjà des entiers.

Je m'attends à ce que ces chiffres soient différents avec chaque version de Ruby, donc il vaut la peine de vérifier la version de votre cible.

+0

En effet, j'ai sauvé plus de 2 secondes avec un tableau de plus de 1mln éléments (Ruby 1.9.1) met [1,2,3 ..... n] .map {| c | c + 48} .pack ("c *") – astropanic

0

La lenteur que vous programme ne vient pas de to_s être appelé 4 fois, mais de l'impression à la console. La sortie de la console est lente et vous ne pouvez rien y faire.

+0

Pas vraiment, bien sûr, la sortie console est lente, mais il existe de nombreuses astuces pour l'améliorer, jetez un oeil par exemple à ceci: http://stackoverflow.com/questions/3334294/ruby-fast-reading-from-std – astropanic

+0

Je serais d'accord avec FRotthowe sur celui-ci. La limitation est l'impression de la console elle-même, pas la façon dont les informations sont transmises à la console. Par l'apparence des deux messages, essayez-vous d'envoyer des données d'un script à un autre via une redirection d'entrée/sortie? –

+0

@ Ank-Kiet Ngo, oui, je manipule un tableau d'entiers et j'ai besoin de le retourner sur stdout, le tableau est vraiment grand, donc les opérations to_s prennent le plus de temps (ruby-prof) – astropanic

0

Pour un seul chiffre, vous pouvez le faire

[1,2,3,4,5].map{|x|(x+48).chr}.join 

Si vous avez besoin d'accélérer un plus grand nombre, vous pouvez essayer memoizing le résultat de to_s

+0

Je doute beaucoup que ce soit réellement plus rapide. Et comme il s'avère qu'un benchmark rapide montre que map + chr + join prend environ 1,75 fois plus longtemps qu'une simple jointure. – sepp2k

3

Si vous souhaitez imprimer un nombre entier à stdout, vous devez d'abord le convertir en chaîne, puisque c'est tout ce que stdout comprend. Si vous souhaitez imprimer deux entiers sur stdout, vous devez d'abord convertir les deux en une chaîne. Si vous voulez imprimer trois entiers sur stdout, vous devez d'abord convertir les trois entiers en une chaîne. Si vous voulez imprimer un milliard d'entiers sur stdout, vous devez d'abord convertir un milliard d'entiers en une chaîne.

Il n'y a rien que vous, nous, ou Ruby, ou vraiment n'importe quel langage de programmation puisse faire à ce sujet.

Vous pouvez essayer d'entrelacer la conversion avec les E/S en effectuant une mise en œuvre de flux lente. Vous pouvez essayer de faire la conversion et l'E/S en parallèle, en effectuant une implémentation de flux paresseux et en séparant la conversion et l'E/S en deux threads distincts.(Assurez-vous d'utiliser une implémentation Ruby qui peut réellement exécuter fils parallèles, pas tous peuvent:. IRM, YARV et Rubinius ne peuvent pas, par exemple)

Vous pouvez paralléliser la conversion, en convertissant des morceaux séparés dans le tableau dans des threads séparés en parallèle. Vous pouvez même acheter une machine d'un milliard de cœurs et convertir tous les milliards d'entiers en même temps en parallèle.

Mais même alors, le fait demeure: chaque entier doit être converti. Que vous le fassiez l'un après l'autre en premier, puis imprimez-les ou faites-les l'un après l'autre entrelacés avec les E/S ou faites-les l'un après l'autre en parallèle avec les E/S ou convertissez-les tous en même temps temps sur un processeur central de milliards: le nombre de conversions nécessaires ne diminue pas de façon magique. Un grand nombre d'entiers signifie un grand nombre de conversions. Même si vous effectuez toutes les conversions milliards dans un processeur de base de milliards en parallèle, il est toujours un milliard de conversions, c'est-à-dire un milliard d'appels à to_s.

0

Sauf si vous avez vraiment besoin de voir les chiffres sur la console (et cela sonne comme vous ne le faites pas), puis les écrire dans un fichier en binaire - devrait être beaucoup plus rapide.

Et vous pouvez diriger des fichiers binaires vers d'autres programmes si c'est ce que vous devez faire, pas seulement du texte.