I am trying to solve a problem where I need to find the airport code in an array of arrays of that represents the starting point of a multi-city flight plan. For example: Given
If you think with Ruby's syntax in mind, just take a transpose and take out all arrivals from departures.
def flight_origin(arr)
plan = arr.transpose
plan[0].index((plan[0] - plan[1])[0])
end
flight_origin([['LAX', 'BWI'], ['BOS', 'SEA'], ['HNL', 'LAX'], ['SEA', 'HNL']]) # => 1
HTH
You could do this:
legs = [['LAX', 'BWI'], ['BOS', 'SEA'], ['HNL', 'LAX'], ['SEA', 'HNL']]
airports = legs.flatten
#=> ["LAX", "BWI", "BOS", "SEA", "HNL", "LAX", "SEA", "HNL"]
legs.map(&:first).find { |ap| airports.count(ap) == 1 }
#=> "BOS"
This could instead be written using Array#transpose (as has been done in other answers) or Enumerable#zip since:
legs.map(&:first)
#=> ["LAX", "BOS", "HNL", "SEA"]
legs.transpose.first
#=> ["LAX", "BOS", "HNL", "SEA"]
legs.first.zip(*legs[1..-1]).first
#=> ["LAX", "BOS", "HNL", "SEA"]
My main reason for answering, however, is to make a plug for the method Array#difference
, which I'd like to see in some future Ruby version. It is defined here.
With it, we can write:
airports = legs.flatten
#=> ["LAX", "BWI", "BOS", "SEA", "HNL", "LAX", "SEA", "HNL"]
(legs.map(&:first) - airports.difference(airports.uniq)).first
#=> "BOS"
Note that:
airports.difference(airports.uniq)
#=> ["LAX", "SEA", "HNL"]
contains all airports that appear more than once in the legs; that is, all all the "intermediate" airports.
trips = [['LAX', 'BWI'], ['BOS', 'SEA'], ['HNL', 'LAX'], ['SEA', 'HNL']]
arrivals = trips.map(&:last)
p trips.find{|fligth| ! arrivals.include? fligth[0] } #=> ["BOS", "SEA"]
sorry i, have no enough time to explain my code - but i think nothing is such difficult not to figure out what is happening :)
here is the working example
def find_start_point(list)
start = []
finish = []
list.each do |l|
start.push(l[0])
finish.push(l[1])
end
start.each do |st|
if !finish.include? st
return start.index(st)
end
end
end
Building on dwenzel's idea:
airports = [['LAX', 'BWI'], ['BOS', 'SEA'], ['HNL', 'LAX'], ['SEA', 'HNL']]
departures, arrivals = airports.transpose
first_departure_index = departures.index{|dep| !arrivals.include?(dep)}
I see what you're attempting. The originating airport would be the only one included in a 0 index of a sub array but not a 1 index of any sub array.
However, in you're solution, you are comparing each combination of 2 sub arrays (including a sub array and itself, by the way...), and then returning the index of list
if a[0] != b[1]
is ever true for sub array a
. This is returning too many results, and you'll always end up returning the last index. For example, 'SEA', the 0 index of the 3rd sub array, does not equal 'BWI', the 1 index of the 0 sub array, so your start_point
now equals 3.
I won't do all of your work for you :), but let me suggest this: When you're going through your iterations, keep track of which sub arrays' index 0 ever equals a different sub array's index 1. Your answer will be the only one not included in this list.
Edit: Continue to work through my above suggestion for good practice, but here's a real quick and short solution:
def find_start_point(list)
list.each_with_index do |sub, idx|
return idx if list.flatten.count(sub[0]) == 1
end
end
This works by returning the index of the sub array with an index 0 where there are no other occurrences of that airport (by flattening the entire array and using #count
)