Afrahsh
Afrahsh

Reputation: 61

Iterating over a hash with arrays as value

I am asking a user for key currentline and value currentstation in order to compare it against a hash, and display which line to travel.

mtahash = {
  n: ["timesq", "34thn", "28thn", "23rdn", "Union_Square", "8th"],
  l: ["8th", "6th", "Union_Square", "3rd", "1st"],
  s: ["Grand Central", "33rds", "28th", "23rds", "Union Square", "Astor Place"]
}

puts "Please enter your current station"
current_station = gets.chomp
puts "Please enter your current line"
current_line = gets.chomp

mtahash.each do |key, value|
  if key == current_line && value == current_station
    puts "got it"
  else
    puts "fish"
  end
end

My code outputs fish three times regardless of the input.

Upvotes: 2

Views: 131

Answers (3)

mrzasa
mrzasa

Reputation: 23317

A value in this iteration is an array. You should be checking if it includes station name, not if it's equal to it. Also transform key to string with key.to_s (it's a symbol now):

 mtahash.each do |key, value|
   if key.to_s == current_line && value.include?(current_station)
     puts "got it"
   else
     puts "fish"
   end
 end

Upvotes: 1

iGian
iGian

Reputation: 11193

I'd suggest to convert to_sym (String#to_sym) the user input for current_line, since the hash keys are symbols.

Then check if the hash has that key (Hash#has_key).

Finally access the hash by key and check if the array includes (Array#include) the current_station, since values of the hash are arrays.

This is just a snippet as example.

current_station = "timesq" # gets.chomp
current_line = "n".to_sym  # gets.chomp.to_sym <--- note .to_sym

if mtahash.has_key? current_line
    if mtahash[current_line].include? current_station
      then puts "got it"
      else puts "fish"
    end
  else puts "no line"
end


Even better, invert the input sequence, check the mtahash.has_key? after the user enters the line, if true go asking for the station.

Upvotes: 0

ray
ray

Reputation: 5552

each will iterate for each key value (even if one match is found) but detect will stop once it got found match.

I think keys for hash is unique so detect is better than using each

mtahash.detect { |k, v| k.to_s == current_line && v.include?(current_station) } ? 'got it' : 'fish'

Reduce iterations.

 > mtahash = {:n=>["timesq", "34thn", "28thn", "23rdn", "Union_Square", "8th"], :l=>["8th", "6th", "Union_Square", "3rd", "1st"], :s=>["Grand Central", "33rds", "28th", "23rds", "Union Square", "Astor Place"]} 
 >   current_line, current_station = 'l', '3rd'
 => ["l", "3rd"] 

 > mtahash.detect { |k, v| k.to_s == current_line && v.include?(current_station) } ? 'got it' : 'fish'
 => "got it" 

 > current_line, current_station = 'l', '43rd'
 => ["l", "43rd"] 

 > mtahash.detect { |k, v| k.to_s == current_line && v.include?(current_station) } ? 'got it' : 'fish'
 => "fish" 

Upvotes: 0

Related Questions