我有以下代码可以使用
def add_item!(item, list)
list << item
list # this is what we return from the method
end
如果我有物品就行了。
add_item!(2, "henk")
add_item!(3, "george")
但是我想要检查项目是否已经在列表中。我想过用list.include做这个吗?功能。如果我尝试这个我得到
def add_item! (item, list)
if list.include?(item)
list << item
list
else
puts "This is a double item"
end
end
add_item!(2, "list")
add_item!(2, "list")
然而,这会给我带来以下错误:
TypeError: can't convert Fixnum into String
我不明白为什么会这样,可以避免这种情况。有什么想法吗?
答案 0 :(得分:3)
如果您需要列表,并且不想要重复,那么请不要使用数组,请使用Set:
Set实现无序值的集合,没有重复项。这是Array直观的互操作设施和Hash快速查找的混合体。
不必担心某些事物是否已存在,您可以将代码保持为:
require 'set'
the_set = [].to_set
def add_item!(item, list)
list << item
end
add_item!('foo', the_set)
the_set # => #<Set: {"foo"}>
add_item!('bar', the_set)
the_set # => #<Set: {"foo", "bar"}>
add_item!('foo', the_set)
the_set # => #<Set: {"foo", "bar"}>
如果您需要它作为数组,请使用to_a
:
the_set.to_a # => ["foo", "bar"]
但实际上,不是创建一个真正无法减少代码的方法,只需使用<<
:
add_item!('foo', the_set)
the_set # => #<Set: {"foo"}>
the_set << 'bar'
the_set # => #<Set: {"foo", "bar"}>
它更短,比调用方法更快。
在我看来,通过将单个操作移动到方法中来干燥代码并不能提供帮助,并且从长远来看可能会使事情变得更糟,因为操作是隐藏的。
但是我想要检查项目是否已经在列表中。我想过用list.include做这个吗?功能。如果我尝试这个我得到
if list.include?(item)
仔细查看条件测试。如果if list.include?(item)
表示&#34;项目在列表&#34;中,是否要附加到list
变量?
答案 1 :(得分:0)
我同意The Tin Man的回答 - Set
是保持独特收藏的最佳方式。您的代码引发的异常有什么问题 - 仔细看看您做了什么:
add_item!(2, "henk")
您实际上是将Integer
添加到String
:
'henk' << 2
# => "henk\u0002"
在第二种情况下
add_item!(2, "list")
你完全一样:
"list".include?(2)
TypeError: no implicit conversion of Fixnum into String
因此,您只需将Array
或Set
传递给您的方法,而不是String
。
my_array = []
add_item!(2, my_array)
另请仔细查看您的if
- 声明
if list.include?(item)
list << item
list
else
puts "This is a double item"
end
如果项目已经存在,那么您将要添加一个项目,这显然不是您想要达到的目标,因此您实际应该使用unless
代替if
或反过来:
if list.include?(item)
puts "This is a double item"
else
list << item
list
end
另外与Array
进行合作,您可以通过
list |= [item]
例如:
my_array = []
# => []
my_array |= [1]
# => [1]
my_array |= [1]
# => [1]