Рубиновое быстрое чтение с STD - PullRequest
0 голосов
/ 26 июля 2010

Какой самый быстрый способ прочитать из STDIN число 1000000 символов (целых чисел) и разделить его на массив из однозначных целых чисел (не строк)?

123456 > [1,2,3,4,5,6]

Ответы [ 3 ]

5 голосов
/ 26 июля 2010

Самый быстрый метод, который я нашел на данный момент, выглядит следующим образом: -

  gets.unpack("c*").map { |c| c-48}

Вот некоторые результаты сравнительного анализа большинства предоставленных решений.Эти тесты были выполнены с файлом из 100 000 цифр, но с 10 повторениями для каждого теста.


                                  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)

А вот код, который их создал

#!/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
2 голосов
/ 26 июля 2010

Это должно быть достаточно быстро:

a = []
STDIN.each_char do |c|
  a << c.to_i
end

хотя некоторые грубые тесты показывают, что эта хакерская версия значительно быстрее

a = STDIN.bytes.map { |c| c-48 }
0 голосов
/ 26 июля 2010
scan(/\d/).map(&:to_i)

Это разделит любую строку на массив целых чисел, игнорируя любые нечисловые символы. Если вы хотите получить пользовательский ввод из STDIN, добавьте:

gets.scan(/\d/).map(&:to_i)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...