Найти уникальный элемент в составном массиве

Я пытаюсь решить проблему, когда мне нужно найти код аэропорта в массиве массивов, который представляет собой отправную точку многолетнего плана полета. Например: для массива [['LAX', 'BWI'], ['BOS', 'SEA'], ['HNL', 'LAX'], ['SEA', 'HNL']], где первый индексом каждого вспомогательного массива является выездной аэропорт, а второй - аэропорт назначения, мне нужно найти индексный пункт, откуда начинается полет, в этом случае метод вернет 1, чтобы представлять ['BOS', 'SEA'].

Этот код не работает и всегда возвращает последний элемент в массиве

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

Ответ 1

Я вижу, что вы пытаетесь. Исходный аэропорт будет единственным, включенным в индекс 0 вспомогательного массива, но не одним индексом любого дополнительного массива.

Однако в вашем решении вы сравниваете каждую комбинацию из двух подматриц (включая вспомогательный массив и сам, кстати...), а затем возвращаем индекс list, если a[0] != b[1] когда-либо true для вспомогательного массива a. Это возвращает слишком много результатов, и вы всегда будете возвращать последний индекс. Например, "SEA", индекс 0 третьего вспомогательного массива, не соответствует "BWI", 1 индексу 0-массива 0, поэтому ваш start_point теперь равен 3.

Я не буду делать всю вашу работу за вас:), но позвольте мне предложить следующее: когда вы проходите через свои итерации, следите за тем, какой индекс вспомогательных массивов 0 когда-либо равен другому индексу sub-массива 1. Ваш ответ будет единственным, не включенным в этот список.

Изменить: Продолжайте работать по моему предложению о хорошей практике, но здесь действительно быстрое и короткое решение:

def find_start_point(list)
  list.each_with_index do |sub, idx|
    return idx if list.flatten.count(sub[0]) == 1
  end
end

Это работает, возвращая индекс вспомогательного массива с индексом 0, где нет других вхождений этого аэропорта (путем сглаживания всего массива и использования #count)

Ответ 2

Извините, у меня недостаточно времени, чтобы объяснить мой код, - но я думаю, что нет ничего сложного, чтобы не понять, что происходит:)

вот рабочий пример

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

Ответ 3

Основываясь на идее двензеля:

airports = [['LAX', 'BWI'], ['BOS', 'SEA'], ['HNL', 'LAX'], ['SEA', 'HNL']]

departures, arrivals = airports.transpose

first_departure_index = departures.index{|dep| !arrivals.include?(dep)}

Ответ 4

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

Ответ 5

Если вы думаете с учетом синтаксиса Ruby, просто возьмите транспонирование и выведете всех прибывших из вылетов.

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

НТН

Ответ 6

Вы можете сделать это:

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"

Это можно было бы записать с помощью Array # transpose (как это было сделано в других ответах) или Переменная # zip с:

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"] 

Моей главной причиной для ответа, однако, является создание плагина для метода Array#difference, который я хотел бы увидеть в будущей версии Ruby. Он определен здесь.

С его помощью мы можем написать:

airports = legs.flatten 
  #=> ["LAX", "BWI", "BOS", "SEA", "HNL", "LAX", "SEA", "HNL"] 
(legs.map(&:first) - airports.difference(airports.uniq)).first
  #=> "BOS" 

Обратите внимание, что:

airports.difference(airports.uniq)
  #=> ["LAX", "SEA", "HNL"]

содержит все аэропорты, которые появляются более одного раза в ногах; то есть все "промежуточные" аэропорты.

Ответ 7

trips = [['LAX', 'BWI'], ['BOS', 'SEA'], ['HNL', 'LAX'], ['SEA', 'HNL']]

arrivals = trips.map(&:last)

p trips.find{|fligth| ! arrivals.include? fligth[0] } #=> ["BOS", "SEA"]