2014-02-10 5 views
1

Я пытаюсь объединить два списка на основе позиции индекса, поэтому вид пересечения близости.Объединить два списка по условию

В этом случае комплект не работает. То, что я пытаюсь сделать, - это индекс соответствия в каждом списке, а затем, если элемент меньше, чем элемент в другом списке, только тогда я его собираю.

Пример объяснит мой сценарий лучше.

Пример ввода:

print merge_list([[0, 1, 3], [1, 2], [4, 1, 3, 5]], 
       [[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]]) 

Образец Выход:

[[0,2],[4,6]] 

так далее положение 0 в list1 мы имеем 1, 3 и в list2 мы имеем 2, 6. Так как 1 составляет менее 2, поэтому мы собираем и двигаемся дальше, теперь 3 меньше, чем 6, но это не меньше, чем т. е. не 5, поэтому мы игнорируем это. Далее мы имеем [1, 2] [1, 4], поэтому оба индекса/позиции 1, но 2 не меньше, чем 4, поэтому мы игнорируем это. Далее у нас [2, 2] в списке2 оба индекса 2 не соответствуют ни одному индексу в первом списке, поэтому никакого сравнения. Наконец, мы имеем сравнение [4, 1, 3, 5] [4, 1, 6]. Оба индекса совпадают, и только 5 в списке один на один меньше, чем в списке два, поэтому мы собираем шесть, поэтому мы собираем [4,6], что означает индекс 4 и матч и т. Д.

Я попытался заставить его работать, Кажется, он работает.

Это мой код.

def merge_list(my_list1, my_list2): 
merged_list = [] 
bigger_list = [] 
smaller_list = [] 

temp_outer_index = 0 
temp_inner_index = 0 

if(len(my_list1) > len(my_list2)): 
    bigger_list = my_list1 
    smaller_list = my_list2 
elif(len(my_list2) > len(my_list1)): 
    bigger_list = my_list2 
    smaller_list = my_list1 
else: 
    bigger_list = my_list1 
    smaller_list = my_list2 

for i, sublist in enumerate(bigger_list):    
    for index1 , val in enumerate(sublist):   
      for k, sublist2 in enumerate(smaller_list): 
       for index2, val2 in enumerate(sublist2):      
        temp_outer_index = index1 + 1   
        temp_inner_index = index2 + 1 
        if(temp_inner_index < len(sublist2) and temp_outer_index < len(sublist)): 
         # print "temp_outer:%s , temp_inner:%s, sublist[temp_outer]:%s, sublist2[temp_inner_index]:%s" % (temp_outer_index, temp_inner_index, sublist[temp_outer_index], sublist2[temp_inner_index]) 
         if(sublist2[temp_inner_index] < sublist[temp_outer_index]): 
          merged_list.append(sublist[temp_outer_index]) 
          break 


return merged_list 
+0

Не было бы [[1, 3], [2], [], [], [1, 3, 5]] и [[2, 6], [4], [2], [], [1, 6]] 'делает гораздо больше смысла в качестве входных данных, поэтому индекс * является фактическим индексом? – poke

+0

@poke, спасибо за ваш комментарий. В моем другом коде мы создаем их, я только создаю те, у которых есть данные, т. Е. Нет []. Я знаю, что это делается с большей готовностью, но не требуется, и я думаю, что не эффективен и т. Д. – user3247054

ответ

2

Не знаете, что вы делаете, но это должно сработать.

Во-первых, преобразовать список списков для отображения индексов для набора цифр, содержащихся в этом списке:

def convert_list(l): 
    return dict((sublist[0], set(sublist[1:])) for sublist in l) 

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

>>> convert_list([[0, 1, 3], [1, 2], [4, 1, 3, 5]]) 
{0: set([1, 3]), 1: set([2]), 4: set([1, 3, 5])} 
>>> convert_list([[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]]) 
{0: set([2, 6]), 1: set([4]), 2: set([2]), 4: set([1, 6])} 

Теперь функция merge_lists можно записать так:

def merge_lists(l1, l2): 
    result = [] 
    d1 = convert_list(l1) 
    d2 = convert_list(l2) 
    for index, l2_nums in d2.items(): 
     if index not in d1: 
      #no matching index 
      continue 
     l1_nums = d1[index] 
     sub_nums = [l2_num for l2_num in l2_nums if l2_num - 1 in l1_nums] 
     if sub_nums: 
      result.append([index] + sorted(list(sub_nums))) 
    return result 

работает для вашего теста:

>>> print merge_lists([[0, 1, 3], [1, 2], [4, 1, 3, 5]], 
         [[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]]) 
[[0, 2], [4, 6]] 
+0

Большое спасибо за вашу помощь и ответ. Проверяя это сейчас. – user3247054

+0

- это производительность для больших списков квадратичных или линейных для больших списков с использованием этого решения? – user3247054

+0

Он линейный. Вы в основном касаетесь всего постоянного количества раз. – Claudiu

1

Я считаю, что это делает то, что вы хотите сделать:

import itertools 

def to_dict(lst): 
    dct = {sub[0]: sub[1:] for sub in lst} 
    return dct 

def merge_dicts(a, b): 
    result = [] 
    overlapping_keys = set.intersection(set(a.keys()), set(b.keys())) 
    for key in overlapping_keys: 
     temp = [key] # initialize sublist with index 
     for i, j in itertools.product(a[key], b[key]): 
      if i == j - 1: 
       temp.append(j) 
     if len(temp) > 1: # if the sublist has anything besides the index 
      result.append(temp) 
    return result 

dict1 = to_dict([[0, 1, 3], [1, 2], [4, 1, 3, 5]]) 
dict2 = to_dict([[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]]) 

result = merge_dicts(dict1, dict2) 
print(result) 

Результат:

[[0, 2], [4, 6]] 

Во-первых, мы превращаем ваши списки dicts, потому что они легче работать с (это отделяет ключ от других значений). Затем мы ищем ключи, которые существуют в обоих dicts (в примере, это 0, 1, 4) и посмотрите на все пары значений между двумя dicts для каждой клавиши (в примере 1,2, 1, 6, 3,2, 3,6, 2,4, 1,1, 1,6, 3,1, 3,6, 5,1, 5,6). Всякий раз, когда первый элемент пары меньше, чем второй элемент, мы добавляем второй элемент в наш список temp. Если список temp заканчивается, содержащий что-либо помимо ключа (т. Е. Длиннее 1), мы добавляем его в список result, который мы в конце концов возвращаем.

(Мне пришло в голову, что это имеет очень плохие характеристики производительности - квадратичные по длине подсписок - так что вы можете захотеть использовать ответ Клаудиу, если ваши подсписки будут длинными. Если они собираются быть коротким, хотя, я думаю, что стоимость инициализации набора достаточно велико, что мое решение может быть быстрее.)

+0

Большое спасибо за ваш ответ. Проверяя это сейчас. – user3247054

+0

Хотелось бы, чтобы я согласился с вашим ответом, основываясь на большом объяснении и последней части производительности. Списки будут большими, поэтому производительность действительно вызывает беспокойство. Как claudiu лучше с точки зрения производительности по сравнению с вашим решением? – user3247054

+1

@ user3247054 Предположим, что у вас есть 1000-элементный подсписчик с тем же индексом в 'list1' и' list2'. Для цикла 'itertools.product' здесь потребуется 1000^2 = один миллион циклов. Решение Claudiu будет требовать только 1000 циклов (в понимании списка), но также и множество тестов на членство в группе (хотя это только линейное число). Вы знаете, что ваши данные выглядят лучше, чем мы, поэтому вы можете проверить оба наших решения и посмотреть, какой из них выходит быстрее. – senshin

1
def merge_list(a, b): 
    d = dict((val[0], set(val[1:])) for val in a) 
    result = [] 
    for val in b: 
     k = val[0] 
     if k in d: 
      match = [x for x in val[1:] if x - 1 in d[k]] 
      if match: 
       result.append([k] + match) 
    return result 

Подобно другим ответам, это будет первым преобразовать один из списков в словарь с первый элемент каждого внутреннего списка в качестве ключа, а остальная часть списка - как значение. Затем мы переходим через другой список, и если первый элемент существует как ключ в словаре, мы находим все значения, соответствующие вашим критериям, используя понимание списка, и если они есть, добавьте запись в список result, который возвращается на конец.

Смежные вопросы