Quel est le moyen le plus rapide de lire à partir de STDIN un nombre de 1000000 caractères (entiers), et le diviser en un tableau d'entiers d'un caractère (pas de chaînes)?ruby lecture rapide de std
123456 > [1,2,3,4,5,6]
Quel est le moyen le plus rapide de lire à partir de STDIN un nombre de 1000000 caractères (entiers), et le diviser en un tableau d'entiers d'un caractère (pas de chaînes)?ruby lecture rapide de std
123456 > [1,2,3,4,5,6]
Cela devrait être assez rapide:
a = []
STDIN.each_char do |c|
a << c.to_i
end
bien que certains étalonnage bruts montre cette version hackish est beaucoup plus rapide:
a = STDIN.bytes.map { |c| c-48 }
scan(/\d/).map(&:to_i)
Cela diviser une chaîne en un tableau des entiers, en ignorant tous les caractères non numériques. Si vous voulez saisir l'entrée utilisateur de STDIN ajouter obtient:
gets.scan(/\d/).map(&:to_i)
La méthode la plus rapide que je l'ai trouvé à ce jour est la suivante: -
gets.unpack("c*").map { |c| c-48}
Voici quelques résultats de l'analyse comparative la plupart des solutions proposées . Ces tests ont été exécutés avec un fichier de 100 000 chiffres mais avec 10 répétitions pour chaque test.
user system total real each_char_full_array: 1.780000 0.010000 1.790000 ( 1.788893) each_char_empty_array: 1.560000 0.010000 1.570000 ( 1.572162) map_byte: 0.760000 0.010000 0.770000 ( 0.773848) gets_scan 2.220000 0.030000 2.250000 ( 2.250076) unpack: 0.510000 0.020000 0.530000 ( 0.529376)
Et voici le code qui les produit
#!/usr/bin/env ruby
require "benchmark"
MAX_ITERATIONS = 100000
FILE_NAME = "1_million_digits"
def build_test_file
File.open(FILE_NAME, "w") do |f|
MAX_ITERATIONS.times {|x| f.syswrite rand(10)}
end
end
def each_char_empty_array
STDIN.reopen(FILE_NAME)
a = []
STDIN.each_char do |c|
a << c.to_i
end
a
end
def each_char_full_array
STDIN.reopen(FILE_NAME)
a = Array.new(MAX_ITERATIONS)
idx = 0
STDIN.each_char do |c|
a[idx] = c.to_i
idx += 1
end
a
end
def map_byte()
STDIN.reopen(FILE_NAME)
a = STDIN.bytes.map { |c| c-48 }
a[-1] == -38 && a.pop
a
end
def gets_scan
STDIN.reopen(FILE_NAME)
gets.scan(/\d/).map(&:to_i)
end
def unpack
STDIN.reopen(FILE_NAME)
gets.unpack("c*").map { |c| c-48}
end
reps = 10
build_test_file
Benchmark.bm(10) do |x|
x.report("each_char_full_array: ") { reps.times {|y| each_char_full_array}}
x.report("each_char_empty_array:") { reps.times {|y| each_char_empty_array}}
x.report("map_byte: ") { reps.times {|y| map_byte}}
x.report("gets_scan ") { reps.times {|y| gets_scan}}
x.report("unpack: ") { reps.times {|y| unpack}}
end
quel est le moyen le plus rapide de prendre stdin de lignes de coordonnées comme 0 10 \ n 89 23 \ n 45 32 \ n 3 54 etc et de créer un objet ponctuel de chacun ainsi Point.new (firstnum, secondnum) – Evan
de Nice, beaucoup plus rapide que la méthode obtient, grâce – astropanic
bien aussi, mais comment avez-vous le suppriment -38 à la fin? – astropanic
Vous pouvez exécuter '[0 ...- 1]' sur le tableau résultant, mais généralement, sauf si vous en avez absolument besoin pour être aussi rapide que possible, je vous conseille d'utiliser une validation, en utilisant 'select' ou' rejeter », par exemple. Si la vitesse est critique, vous ne devriez pas utiliser Ruby pour commencer. –