@members = {
approved: ["Jill"],
unapproved: ["Daniel"],
removed: ["John"],
banned: ["Daniel", "Jane"]
}
Very simply: making a program to track membership. In the above hash you can see the four membership status keys each with an array containing names.
I'm trying to create a find_member method which allows the user to enter a name and then searches each array for the name and tells the user which key the name was found in.
I'm not very good with hashes and in attempting to do this I've created a mess of loops and I imagine there's a very easy solution, I just haven't found it so far. Is there a really simple way to do this?
I've tried a few things and don't have all my past efforts still, but this is the latest mess I've ended up with, which is probably worse than what I had previously:
def find_member
puts "==Find Member=="
puts "Name: "
@name = gets.chomp
@members.each do |key|
key.values.each do |array|
array.each do |element|
if @name == element
puts "#{@name} found in #{key}"
else
puts "#{@name} not found in #{key}"
end
end
end
end
end
Thanks.
You can use this itteration with include?
method.
@members = {
approved: ["Jill"],
unapproved: ["Daniel"],
removed: ["John"],
banned: ["Daniel", "Jane"]
}
def find_member_group(name)
@members.each { |group, names| return group if names.include?(name) }
nil
end
@name = 'Jane'
group_name = find_member_group(@name)
puts group_name ? "#{@name} found in #{group_name}." : "#{@name} not found."
# => Jane found in banned.
Hash#select is the method to use here:
def find_member(name)
@members.select {|k,v| v.include? name }.keys
end
find_member("Jill") #=> [:approved]
find_member("Daniel") #=> [:unapproved, :banned]
find_member("John") #=> [:removed]
find_member("Jane") #=> [:banned]
Explanation:
select
as the name suggests selects and maps only those elements that satisfy the condition in the corresponding code-block. The code-block negates the need for an if
statement. Within the code-block we check each key-value pair and if its value includes the name
argument, then that key-value pair is selected and mapped to the final output. Finally we're only interested in the memberships (namely the keys), so we apply the keys
method to get these in the form of an array.
The most efficient way to do this is to create a one-to-many mapping of names to keys, and update that mapping only when @members
changes.
def find_member(name)
update_names_to_keys_if_necessary
@member_to_keys[name]
end
def update_names_to_keys_if_necessary
new_hashcode = @members.hash
return if @old_members.hashcode == new_hashcode
@member_to_keys = @members.each_with_object(Hash.new { |h,k| h[k] = [] }) { |(k,v),h|
v.each { |name| h[name] << k } }
@old_members_hashcode = new_hashcode
end
Note that @old_members_hashcode
evaluates to nil
the first time update_names_to_keys_if_necessary
is called, so @member_to_keys
will be created at that time.
Initially we obtain
@member_to_keys
#=> {"Jill"=>[:approved], "Daniel"=>[:unapproved, :banned],
# "John"=>[:removed], "Jane"=>[:banned]}
Try it.
find_member("Jill")
#=> [:approved]
find_member("Daniel")
#=> [:unapproved, :banned]
find_member("John")
#=> [:removed]
find_member("Jane")
#=> [:banned]
find_member("Billy-Bob")
#=> []
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.