список пониманий с перерывом - PullRequest
1 голос
/ 27 апреля 2020

У меня есть следующий код, который я хотел бы написать в одну строку с пониманием списка.

list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56]

list3 = []
for i in list1:
    for j in list2:
        if j>i:
            # print(i,j)
            list3.append(j)
            break
print(list1)
print(list3)

Вывод:

[4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
[5, 7, 7, 11, 11, 17, 24, 24, 26, 56]

Это оператор break, который выбрасывает меня, я не знаю, где это поставить.

Спасибо

Ответы [ 4 ]

2 голосов
/ 27 апреля 2020

Для построения выражения сначала необходимо игнорировать условие break:

In [32]: [[j for j in list2 if j > i] for i in list1]                                       
Out[32]: 
[[5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
 [7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
 [7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
 [11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
 [11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
 [17, 20, 24, 26, 56],
 [24, 26, 56],
 [24, 26, 56],
 [26, 56],
 [56]]

Оттуда вы можете добавить ограничение min:

In [33]: [min([j for j in list2 if j > i]) for i in list1]                                  
Out[33]: [5, 7, 7, 11, 11, 17, 24, 24, 26, 56]
1 голос
/ 28 апреля 2020

Вы не можете по-настоящему разбить внутреннее понимание списка для l oop, что вы можете сделать, чтобы вообще не разбивать его, используя следующую функцию, чтобы найти первое вхождение соответствующего значения:

list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56]
list3 = [ next(j for j in list2 if j>i) for i in list1 ]

output:

print(list1)
print(list3)
[4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
[5, 7, 7, 11, 11, 17, 24, 24, 26, 56]

Если вы беспокоитесь о производительности (поскольку понимание списка будет медленнее, чем циклы), вы можете использовать разделительный поиск в списке 2, чтобы найти следующее более высокое значение :

from bisect import bisect_left
list3 = [ list2[bisect_left(list2,i+1)] for i in list1 ]

Предполагается, что list2 отсортирован в порядке возрастания и что max (list2)> max (list1)

0 голосов
/ 28 апреля 2020

Вы можете переместить логику прерывания c в отдельную функцию, а затем поместить эту функцию в понимание списка:

def smallest_value_larger_than_i(candidate_values, i):
    for value in candidate_values:
        if value > i:
            return value
    return None  # Not sure how you want to handle this case

list3 = [smallest_value_larger_than_i(list2, i) for i in list1]

Это работает немного медленнее, чем ваше первоначальное решение, но если цель использования понимание списка - это скорость, вы получите гораздо лучшие результаты, улучшив алгоритм. Например, если оба списка отсортированы, вы можете отбросить элементы из list2, как только пропустите их один раз, вместо того, чтобы сравнивать их с остальной частью list1. Вы также можете выполнить бинарный поиск по списку 2 вместо линейного сканирования.

0 голосов
/ 28 апреля 2020

Я попытался определить время ответа AbbeGijly.

Оказывается, это медленнее, чем оригинальное решение. Проверьте это.

import timeit

print(timeit.timeit('''
list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 40, 56]

list3 = []
for i in list1:
    for j in list2:
        if j>i:
            # print(i,j)
            list3.append(j)
            break
'''))

print(timeit.timeit('''
list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 40, 56]
list4 = [[j for j in list2 if j > i] for i in list1]
'''))

Вывод:

3.6144596
8.731578200000001
...