0

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 an array [['LAX', 'BWI'], ['BOS', 'SEA'], ['HNL', 'LAX'], ['SEA', 'HNL']] where the first index of each sub array is the departing airport and the second is the destination airport, I need to find the index point where the flight originates, in this case the method would return 1 to represent ['BOS', 'SEA'].

This code does not work and always returns the last element in the array

def find_start_point(list)
  start_point = nil
  list.each do |a|
    list.each do |b|
      if a[0] != b[1]
        start_point = list.index(a)
      end
    end
  end
  start_point
end
NickTerrafranca
  • 109
  • 1
  • 8

7 Answers7

1

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)

dwenzel
  • 1,404
  • 9
  • 15
0

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
marmeladze
  • 6,468
  • 3
  • 24
  • 45
0

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)}
user12341234
  • 6,573
  • 6
  • 23
  • 48
0
def find_start(arr)
  flat = arr.flatten
  first, second = flat.reject { |val| flat.count(val) > 1}
  start_city = if flat.index(first) % 2 == 0 #if index of first is even
                 first
               else
                 second
               end
  arr.find { |pair| pair[0] == start_city }
end
mmartinson
  • 242
  • 1
  • 3
  • 13
  • If I understand the problem correctly, if you flattened the array, meaning removing all the nested arrays while maintaining the contents in a single array in the same order, then the only two unique elements of this array would be the start and end city. We know that the start city is either the first, third, fifth, etc element in the flattened array, meaning it has an even index, so we just figure out which of the two unique values has an even index, then we have the start – mmartinson Apr 12 '15 at 01:16
  • That's not how the uniq method works. It would return an array of ALL airports, with no repeats. so `arr.flatten.uniq` is `["LAX", "BWI", "BOS", "SEA", "HNL"]` That would not work here. – dwenzel Apr 12 '15 at 01:19
  • `first, second = [x,y]` is the same as `first = [x,y][0]` and `second = [x,y][1]` – mmartinson Apr 12 '15 at 01:19
  • Have you tried running your code and verifying the results? Like @dwenzel, that's not how `uniq` works. – Harsh Gupta Apr 12 '15 at 01:21
  • Hey apologies for that, completely slipped my mind that that method was doing something different. The edited version works with an extra step added. – mmartinson Apr 12 '15 at 01:58
0

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

Harsh Gupta
  • 4,348
  • 2
  • 25
  • 30
0

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.

Community
  • 1
  • 1
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
0
trips = [['LAX', 'BWI'], ['BOS', 'SEA'], ['HNL', 'LAX'], ['SEA', 'HNL']]

arrivals = trips.map(&:last)

p trips.find{|fligth| ! arrivals.include? fligth[0] } #=> ["BOS", "SEA"]
hirolau
  • 13,451
  • 8
  • 35
  • 47