如何在 Ruby 中使用 reduce/inject 而不获取未定义的变量
How to use reduce/inject in Ruby without getting Undefined variable
使用累加器时,累加器是只存在于reduce
块中还是存在于函数中?
我有一个看起来像这样的方法:
def my_useless_function(str)
crazy_letters = ['a','s','d','f','g','h']
str.split.reduce([]) do |new_array, letter|
for a in 0..crazy_letters.length-1
if letter == crazy_letters[a]
new_array << letter
end
end
end
return true if (new_array == new_array.sort)
end
当我执行此代码时出现错误
"undefined variable new_array in line 11 (the return statement)"
我还尝试将 new_array
值分配给另一个变量作为 reduce
块中的 else
语句,但这给了我相同的结果。
有人可以向我解释为什么会这样吗?
块局部变量
new_array
在您的 reduce
调用块之外不存在。这是一个 "block local variable".
reduce
做 return 一个对象,你应该在你的方法中使用它。
sum = [1, 2, 3].reduce(0){ |acc, elem| acc + elem }
puts sum
# 6
puts acc
# undefined local variable or method `acc' for main:Object (NameError)
您的代码
这是您方法的最少更改量:
def my_useless_function(str)
crazy_letters = ['a','s','d','f','g','h']
new_array = str.split(//).reduce([]) do |new_array, letter|
for a in 0..crazy_letters.length-1
if letter == crazy_letters[a]
new_array << letter
end
end
new_array
end
return true if (new_array == new_array.sort)
end
备注:
最后不需要return
。
true if ...
也不需要
for
循环不应在 Ruby 中使用
reduce
returns 块内最后一个表达式的结果。在您的代码中是 for
。
- 如果您总是需要 return
reduce
中的同一对象,这可能是您可以使用 each_with_object
. 的标志
"test".split
就是 ["test"]
String and Enumerable have methods that could help you. Using them, you could write a much cleaner and more efficient method, as in .
问题是new_array
是在调用reduce
的过程中创建的,然后引用就丢失了。 Ruby 中的局部变量的范围是它们所在的块。在您的情况下,数组可以从 reduce
返回,因此您可以在那里使用它。但是,您需要解决一些问题:
str.split
不会将字符串分解为 Ruby 2+ 中的字符。您应该使用 str.chars
或 str.split('')
.
- 为
reduce
的每次新迭代保留的对象必须通过每次从块中返回来保留。最简单的方法是将 new_array
作为块中的最后一个表达式。
因此:
def my_useless_function(str)
crazy_letters = ['a','s','d','f','g','h']
crazy_only = str.split('').reduce([]) do |new_array, letter|
for a in 0..crazy_letters.length-1
if letter == crazy_letters[a]
new_array << letter
end
end
new_array
end
return true if (crazy_only == crazy_only.sort)
end
请注意,您的功能不是很有效,也不是很地道。这是该函数的一个更简短的版本,它更惯用,但效率并不高:
def my_useless_function(str)
crazy_letters = %w[a s d f g h]
crazy_only = str.chars.select{ |c| crazy_letters.include?(c) }
crazy_only == crazy_only.sort # evaluates to true or false
end
这是一个更高效的版本:
def efficient_useless(str)
crazy_only = str.scan(/[asdfgh]/) # use regex to search for the letters you want
crazy_only == crazy_only.sort
end
使用累加器时,累加器是只存在于reduce
块中还是存在于函数中?
我有一个看起来像这样的方法:
def my_useless_function(str)
crazy_letters = ['a','s','d','f','g','h']
str.split.reduce([]) do |new_array, letter|
for a in 0..crazy_letters.length-1
if letter == crazy_letters[a]
new_array << letter
end
end
end
return true if (new_array == new_array.sort)
end
当我执行此代码时出现错误
"undefined variable new_array in line 11 (the return statement)"
我还尝试将 new_array
值分配给另一个变量作为 reduce
块中的 else
语句,但这给了我相同的结果。
有人可以向我解释为什么会这样吗?
块局部变量
new_array
在您的 reduce
调用块之外不存在。这是一个 "block local variable".
reduce
做 return 一个对象,你应该在你的方法中使用它。
sum = [1, 2, 3].reduce(0){ |acc, elem| acc + elem }
puts sum
# 6
puts acc
# undefined local variable or method `acc' for main:Object (NameError)
您的代码
这是您方法的最少更改量:
def my_useless_function(str)
crazy_letters = ['a','s','d','f','g','h']
new_array = str.split(//).reduce([]) do |new_array, letter|
for a in 0..crazy_letters.length-1
if letter == crazy_letters[a]
new_array << letter
end
end
new_array
end
return true if (new_array == new_array.sort)
end
备注:
-
最后不需要
return
。true if ...
也不需要for
循环不应在 Ruby 中使用
reduce
returns 块内最后一个表达式的结果。在您的代码中是for
。- 如果您总是需要 return
reduce
中的同一对象,这可能是您可以使用each_with_object
. 的标志
"test".split
就是["test"]
String and Enumerable have methods that could help you. Using them, you could write a much cleaner and more efficient method, as in
问题是new_array
是在调用reduce
的过程中创建的,然后引用就丢失了。 Ruby 中的局部变量的范围是它们所在的块。在您的情况下,数组可以从 reduce
返回,因此您可以在那里使用它。但是,您需要解决一些问题:
str.split
不会将字符串分解为 Ruby 2+ 中的字符。您应该使用str.chars
或str.split('')
.- 为
reduce
的每次新迭代保留的对象必须通过每次从块中返回来保留。最简单的方法是将new_array
作为块中的最后一个表达式。
因此:
def my_useless_function(str)
crazy_letters = ['a','s','d','f','g','h']
crazy_only = str.split('').reduce([]) do |new_array, letter|
for a in 0..crazy_letters.length-1
if letter == crazy_letters[a]
new_array << letter
end
end
new_array
end
return true if (crazy_only == crazy_only.sort)
end
请注意,您的功能不是很有效,也不是很地道。这是该函数的一个更简短的版本,它更惯用,但效率并不高:
def my_useless_function(str)
crazy_letters = %w[a s d f g h]
crazy_only = str.chars.select{ |c| crazy_letters.include?(c) }
crazy_only == crazy_only.sort # evaluates to true or false
end
这是一个更高效的版本:
def efficient_useless(str)
crazy_only = str.scan(/[asdfgh]/) # use regex to search for the letters you want
crazy_only == crazy_only.sort
end