我正在尝试编写一些循环遍历字符串数组的代码,清理条目,然后将清理后的条目添加到跟踪每个单词出现频率的哈希值。这是我的第一个解决方案:
Dockerfile
它工作正常,但是在数组中循环两次感觉非常低效,所以我一直试图找到一种方法去做,并偶然发现以下内容:
puts("Give me your text.")
text = gets.chomp
words = text.split
frequencies = Hash.new(0)
words.map! do |word|
word.tr("\",.", "")
end
words.each do |word|
frequencies[word] += 1
end
根据我对puts("Give me your text.")
text = gets.chomp
words = text.split
frequencies = Hash.new(0)
words.each_with_index do |word, index|
words[index].tr!("\",.", "")
frequencies[word] += 1
end
的理解,这应该不起作用,但不管怎么说,哈希接收每个字符串的干净版本:https://repl.it/B9Gw。这里发生了什么?如果没有循环两次,有没有不同的方法来解决这个问题?
编辑:经过一些阅读,我能够通过以下方式只使用一个循环来解决问题:
each_with_index
然而,这更像是一个JS或C ++解决方案,并不像惯用的Ruby。还有其他选择吗?另外,为什么puts("Give me your text.")
text = gets.chomp
words = text.split
frequencies = Hash.new(0)
for i in 0..words.length-1
words[i].tr!("\",.", "")
frequencies[words[i]] += 1
end
方法甚至有效?
答案 0 :(得分:3)
您正在使用String#tr!
方法,该方法会破坏性地修改字符串,而不是返回新字符串。你再次查看哈希值(使用words[index]
)的事实不会改变任何东西,因为字符串对象仍然是相同的 - 所以word
用来修改{{1}哈希也被修改了。
有没有不同的方法来解决这个问题而不循环两次?
一种显而易见的方法是使用您使用的相同逻辑,但没有frequencies
(这里没有任何区别)。我建议使用非破坏性with_index
代替String#tr
,以便更清楚地清除哪些字符串以及哪些字符串没有清除。
String#tr!
如果你想明确流程的frequencies = Hash.new(0)
words.each do |word|
cleaned = word.tr("\",.", "")
frequencies[cleaned] += 1
end
阶段并且仍然只循环一次,你可以利用ruby的惰性枚举器:
map
在这里,即使我们执行frequencies = Hash.new(0)
cleaned_words = words.lazy.map { |word| word.tr("\",.", "") }
cleaned_words.each do |cleaned|
frequencies[cleaned] += 1
end
然后执行map
,集合也只会遍历一次,而ruby不会创建任何中间数组。