Создать тестовый файл
Давайте сначала создадим файл 1 .
text =<<-END
/help_page/1 126.318.035.038
/contact 184.123.665.067
/home 184.123.665.067
/about/2 444.701.448.104
/help_page/1 929.398.951.889
/index 444.701.448.104
/help_page/1 722.247.931.582
/about 061.945.150.735
/help_page/1 646.865.545.408
/home 235.313.352.950
END
FNAME = 'log'
File.write(FNAME, text)
#=> 256
Подтвердите его содержание.
puts File.read(FNAME)
/help_page/1 126.318.035.038
/contact 184.123.665.067
/home 184.123.665.067
...
/home 235.313.352.950
Прочитайте файл и создайте полезный хеш
h = File.foreach(FNAME).with_object(Hash.new { |h,k| h[k] = [] }) do |line,h|
key, url = line[1..-2].split
h[key] << url
end
#=> {"help_page/1"=>["126.318.035.038", "929.398.951.889", "722.247.931.582",
# "646.865.545.408"],
# "contact" =>["184.123.665.067"],
# "home" =>["184.123.665.067", "235.313.352.950"],
# "about/2" =>["444.701.448.104"],
# "index" =>["444.701.448.104"],
# "about" =>["061.945.150.735"]}
Используйте этот хэш для вычисления объектов, представляющих интерес
Определение количества просмотров для каждой клавиши
h.transform_values(&:count)
#=> {"help_page/1"=>4, "contact"=>1, "home"=>2, "about/2"=>1, "index"=>1, "about"=>1}
Создать список убывающих просмотров страниц
h.sort_by { |_,a| -a.size }
#=> [["help_page/1", ["126.318.035.038", "929.398.951.889", "722.247.931.582",
# "646.865.545.408"]],
# ["home", ["184.123.665.067", "235.313.352.950"]],
# ["contact", ["184.123.665.067"]],
# ["about/2", ["444.701.448.104"]],
# ["index", ["444.701.448.104"]],
# ["about", ["061.945.150.735"]]]
или, в зависимости от требований:
h.sort_by { |_,a| -a.size }.to_h
#=> {"help_page/1"=>["126.318.035.038", "929.398.951.889", "722.247.931.582",
# "646.865.545.408"],
# "home" =>["184.123.665.067", "235.313.352.950"],
# "contact" =>["184.123.665.067"],
# "about/2" =>["444.701.448.104"],
# "index" =>["444.701.448.104"],
# "about" =>["061.945.150.735"]}
Определите, какие ключи были просмотрены только один раз
h.select { |_,a| a.size == 1 }
#=> {"contact"=>["184.123.665.067"],
# "about/2"=>["444.701.448.104"],
# "index"=>["444.701.448.104"],
# "about"=>["061.945.150.735"]}
Объяснение
См. IO :: write , IO :: read , IO :: foreach , Перечислитель # with_object , Hash :: new , Hash # transform_values , Enumerable # count и Enumerable # sort_by . 2
Вычисление h
альтернативно может быть записано следующим образом.
h = {}
File.foreach(FNAME) do |line|
key, url = line[1..-2].split
h[key] = [] unless h.key?(key)
h[key] << url
end
h
Это объясняет .each_object
и Hash.new { |h,k| h[k] = [] }
. line[1..-2]
обрезает первый символ строки (/
) и символ новой строки ("\n
) в конце строки.
h.transform_values(&:count)
является сокращением для:
h.transform_values { |v| v.count }
1. Для удобства форматирования я выделил каждую строку heredoc ниже 4 пробелов. Для запуска кода сначала удалите отступ строки heredoc.
2. Методы класса и модуля обозначаются двойной двоеточием между классом или модулем и именем метода (например, IO::write
); методы экземпляра обозначаются знаком решетки между классом или модулем и методом экземпляра (например, Enumerator#each_object
). Методы IO
часто вызываются в классе File
(например, File.foreach ...
вместо IO.foreach ...
). Это допустимо, потому что File
является подклассом IO
и поэтому наследует IO
методы класса и экземпляра.