Пример
Давайте применим ваш код к примеру.
str =<<-END
Now is the
time for all
people who are
known to all
of us as the
best coders are
expected to
lead all
those who are
less experienced
to greatness
END
FName = 'temp'
File.write(FName, str)
#=> 146
Ваш код
lines = Array.new()
File.foreach(FName).with_index do |line, line_num|
lines.push(line.split(" ")) if line_num > 0
end
lines
#=> [["time", "for", "all"], ["people", "who", "are"], ["known", "to", "all"],
# ["of", "us", "as", "the"], ["best", "coders", "are"], ["expected", "to"],
# ["lead", "all"], ["those", "who", "are"], ["less", "experienced"],
# ["to", "greatness"]]
indices = lines.map { |el| el.last }
#=> ["all", "are", "all", "the", "are", "to", "all", "are", "experienced", "greatness"]
duplicates = indices.select { |e| indices.count(e) > 2 }
#=> ["all", "are", "all", "are", "all", "are"]
duplicates.uniq
#=> ["all", "are"]
Считается, что объект возвращает массив всех слов, которые появляются как последнее слово строки (кроме первой строки) более двух раз.
Более Ruby-подобный и более эффективный код
Мы можем сделать это более кратко и эффективно, сделав один проход по файлу:
first_line = true
h = Hash.new(0)
File.foreach(FName) do |line|
if first_line
first_line = false
else
h[line[/\S+(?=\n)/]] += 1
end
end
h.select { |_,count| count > 2 }.keys
#=> ["all", "are"]
Выполненные шаги
Шаги следующие.
first_line = true
h = Hash.new(0)
File.foreach(FName) do |line|
if first_line
first_line = false
else
h[line[/\S+(?=\n)/]] += 1
end
end
h #=> {"all"=>3, "are"=>3, "the"=>1, "to"=>1, "experienced"=>1, "greatness"=>1}
g = h.select { |_,count| count > 2 }
#=> {"all"=>3, "are"=>3}
g.keys
#=> ["all", "are"]
Использование Перечислитель # each_object
Вместо того, чтобы определять хеш до выполнения File.foreach(..)
, обычно используется метод Enumerator#each_object
, который позволяет нам связать хэш, который построен для следующих операторов:
first_line = true
File.foreach(FName).with_object(Hash.new(0)) do |line, h|
if first_line
first_line = false
else
h[line[/\S+(?=\n)/]] += 1
end
end.select { |_,count| count > 2 }.keys
#=> ["all", "are"]
Использование счетного хэша
Я определяю хеш следующим образом.
h = Hash.new(0)
Используется форма Hash :: new , которая определяет значение по умолчанию , равное new
s аргументу. Если h = Hash.new(0)
и h
не имеют ключа k
, h[k]
возвращает значение по умолчанию, ноль. Парсер Ruby расширяет выражение h[k] += 1
до:
h[k] = h[k] + 1
Если h
не имеет ключа k
, выражение становится
h[k] = 0 + 1
Обратите внимание, что h[k] = h[k] + 1
является сокращением для:
h.[]=(k, h.[](k) + 1)
Метод Hash#[]
по умолчанию равен нулю, а не метод Hash#[]=
.
Использование регулярного выражения для извлечения последнего слова каждой строки
Одна из строк
str = "known to all\n"
Мы можем использовать регулярное выражение r = /\S+(?=\n)/
, чтобы извлечь последнее слово:
str[r] #=> "all"
Регулярное выражение гласит: «соответствует одному или нескольким (+
) символам, которые не являются пробельными символами (\S
), сразу же после символа новой строки. (?=\n)
- это положительный прогноз . "\n"
должно совпадать, поскольку оно не является частью возвращенного совпадения.