虽然Andrew Marshall 的回答
已经正确,但您也可以在下面尝试这种替代方法。
从您的代码开始,我们可以假设您想要创建一个行为类似于 Hash 的对象,但行为略有不同。因此我们的第一个代码将是这样的。
class Dictionary < Hash
在这里为字典中的某个键分配一个新值会有所不同。从上面的示例中,分配不会用新值替换先前的值,而是将新值推送到先前的值或如果键尚不存在则使用新值初始化的新数组。
这里我使用<<
操作符作为 Array 的 push 方法的简写。此外,该方法返回值,因为它是 super 所做的(参见 if 部分)
def []=(key, value)
if self[key]
self[key] << value
return value # here we mimic what super do
else
super(key, [value])
end
end
使用我们自己的类的优点是我们可以向该类添加新方法,并且所有实例都可以访问它。因此,我们不需要对被认为是危险事物的 Hash 类进行猴子补丁。
def size_of(key)
return self[key].size if self[key]
return 0 # the case for non existing key
end
现在,如果我们结合以上所有内容,我们将得到这段代码
class Dictionary < Hash
def []=(key, value)
if self[key]
self[key] << value
return value
else
super(key, [value])
end
end
def size_of(key)
return self[key].size if self[key]
return 0 # the case for non existing key
end
end
player_emails = Dictionary.new
player_emails["SAO"] = "kirito@sao.com" # note no << operator needed here
player_emails["ALO"] = "lyfa@alo.com"
player_emails["SAO"] = "lizbeth@sao.com"
player_emails["SAO"] = "asuna@sao.com"
player_emails.size_of("SAO") #=> 3
player_emails.size_of("ALO") #=> 1
player_emails.size_of("GGO") #=> 0
p listData
#=> {"SAO" => ["kirito@sao.com", "lizbeth@sao.com", "asuna@sao.com"],
#=> "ALO" => ["lyfa@alo.com"] }
但是,当然,类定义可以用这一行代替
player_emails = Hash.new { [] }
# note that we wont use
#
# player_emails[key] = value
#
# instead
#
# player_emails[key] << value
#
# Oh, if you consider the comment,
# it will no longer considered a single line
答案完成后,我想评论您的一些示例代码:
filename = 'inputfile.txt.'
# Maybe it's better to use ARGF instead,
# so you could supply the filename in the command line
# and, is the filename ended with a dot? O.o;
File.open(filename, 'r').each_line do |line|
# This line open the file anonimously,
# then access each line of the file.
# Please correct me, Is the file will properly closed? I doubt no.
# Saver version:
File.open(filename, 'r') do |file|
file.each_line do |line|
# ...
end
end # the file will closed when we reach here
# ARGF version:
ARGF.each_line do |line|
# ...
end
# Inside the each_line block
line = line.strip.split(/[^[:alpha:]|@|\.]/)
# I don't know what do you mean by that line,
# but using that regex will result
#
# ["listA", "", "", "billg@microsoft.com"]
#
# Hence, your example will fail since
# line[0] == "listA" and line[1] == ""
# also note that your regex mean
#
# any character except:
# letters, '|', '@', '|', '\.'
#
# If you want to split over one or more
# whitespace characters use \s+ instead.
# Hence we could replace it with:
line = line.strip.split(/\s+/)
puts "LIST-> #{line[0]} SUB-> #{line[1]} "
# OK, Is this supposed to debug the line?
# Tips: the simplest way to debug is:
#
# p line
#
# that's all,
listData[line[0]] = ("#{line[1]}")
# why? using (), then "", then #{}
# I suggest:
listData[line[0]] = line[1]
# But to make more simple, actually you could do this instead
key, value = line.strip.split(/\s+/)
listData[key] = value
# Outside the block:
puts '====================================='
# OK, that's too loooooooooong...
puts '=' * 30
# or better assign it to a variable since you use it twice
a = '=' * 30
puts a
p listData # better way to debug
puts a
# next:
print listData.reduce('') { |s, (k, v)|
s << "The key is #{k} and the value is #{v}.\n"
}
# why using reduce?
# for debugging you could use `p listData` instead.
# but since you are printing it, why not iterate for
# each element then print each of that.
listData.each do |k, v|
puts "The key is #{k} and the value is #{v}."
end
好的,不好意思说了这么多,希望对你有帮助。