链接方法(sort_by,reverse等)之后的Ruby重新分配

时间:2019-08-21 07:45:33

标签: ruby syntax

第一次学习Ruby并尝试使用它来学习如何使用它进行功能编程,在我明确想要对其进行更改之前,不要对对象进行更改(使用!

text = "foo bar baz baz baz Foo FOO foo"
# Splitting the sentence into an array of words
words = text.downcase.split(" ") 
# Hash to store the frequencies of each word
frequencies = Hash.new(0) 
# Count the instances of a word one by one
words.each { |word| frequencies[word] += 1 }
# Sort it by the most frequent words
frequencies.sort_by { |word, count| count}.reverse!
# Print out the histogram
frequencies.each { |word, count| puts "#{word} #{count}"}

打印出以下

foo 4
bar 1
baz 3

预期结果将是

foo 4
baz 3
bar 1

我知道这可以解决

frequencies = frequencies.sort_by { |word, count| count}.reverse!

但是我喜欢ruby中简单的!重新分配语法,并且想知道是否可以避免使用此frequencies =吗?


执行frequencies.sort_by! { |word, count| count}.reverse!会引发undefined method错误。

我还发现工作解决方案有点违反直觉,因为它首先解决了

frequencies.sort_by { |word, count| count}

然后将其分配给frequencies =,然后调用下一个方法.reverse!

编辑

我现在认为了解如何阅读有效的解决方案。

frequencies.sort_by { |word, count| count}

返回一个新的哈希,然后由reverse反转。 !不执行任何操作,因为它“重新分配”了没有变量分配的新的(经过排序和反转的)哈希。

然后将整个内容分配给frequencies

1 个答案:

答案 0 :(得分:4)

您似乎只是在进行命令式编程,因为我主要看到的是语句列表。 我建议您将逻辑包装在函数中,以便可以清楚地定义要处理的输入和输出:

def word_frequencies(text)
  words = text.downcase.split(" ") 
  frequencies = Hash.new(0) 
  words.each { |word| frequencies[word] += 1 }
  frequencies.sort_by { |word, count| count}.reverse
end

这样,您可以清楚地说明:

  • 文本是唯一输入
  • 您不会更改输入内容
  • 您不会产生副作用。每次调用该函数时,给定相同的输入,输出将始终相同,唯一的输出将是该函数返回的值。

一旦您清楚地定义了函数的边界,执行分配就不会感到羞耻。

有些时候您需要产生副作用,例如在屏幕上打印一些东西:

frequencies = word_frequencies("foo bar baz baz baz Foo FOO foo")
frequencies.each { |word, count| puts "#{word} #{count}"}

最后,如果您要尝试使用完全链接的程序,可以使用Object#then

"foo bar baz baz baz Foo FOO foo".then do |text|
  text.downcase.split(" ")
end.then do |words|
  words.each_with_object(Hash.new(0)) do |word, memo|
    memo[word] += 1
  end
end.then do |frequencies|
  frequencies.
    sort_by { |word, count| count}.
    reverse
end.each do |word, count|
  puts "#{word} #{count}"
end

# foo 4
# baz 3
# bar 1

选择你的毒药。 :-)