2014-09-04 2 views
6

Недавно я искал способ сгладить вложенный список python, например: [[1,2,3], [4,5,6]], в это: [1,2,3,4,5, 6].Как распознается список, чтобы сгладить список python?

Stackoverflow был полезным, как никогда, и я нашел a post с этим гениальным список понимания:

l = [[1,2,3],[4,5,6]] 
flattened_l = [item for sublist in l for item in sublist] 

Я думал, что я понял, как работает списочные, но, видимо, я не имею ни малейшего представления. Что озадачивает меня больше всего в том, что помимо выше понимания, это также работает (хотя это не дает тот же результат):

exactly_the_same_as_l = [item for item in sublist for sublist in l] 

Может кто-нибудь объяснить, как питон интерпретирует эти вещи? Основываясь на втором составе, я бы ожидал, что питон интерпретирует его обратно, но, видимо, это не всегда так. Если это так, первое понимание должно вызвать ошибку, потому что «подписок» не существует. Мой ум полностью извращен, помогите!

+1

Лучшим способом является переход к нормальному для циклов и использование печати, чтобы увидеть, что происходит –

+6

Второе понимание работает только потому, что 'item' и' sublist' сохраняют свои окончательные значения от первого понимания. Запустите этот первый (или 'del item; del sublist', а затем сделайте это), и он будет давать' NameError', как ожидалось. Странность здесь приведена в правилах определения Python, а не в понимании. –

+1

@MarkWhitfield Только в python2 ... в python3 list-comprehensions ведут себя как genexps и не пропускают переменные во внешней области. – Bakuriu

ответ

4

Давайте посмотрим на ваше понимание списка, но сначала давайте начнем с понимания списка, когда это будет проще всего.

l = [1,2,3,4,5] 
print [x for x in l] # prints [1, 2, 3, 4, 5] 

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

for x in l: 
    print x 

Теперь давайте посмотрим на другой:

l = [1,2,3,4,5] 
a = [x for x in l if x % 2 == 0] 
print a # prints [2,4] 

То есть точно так же, как это :

a = [] 
l = [1,2,3,4,5] 
for x in l: 
    if x % 2 == 0: 
     a.append(x) 
print a # prints [2,4] 

Теперь давайте возьмем посмотрите примеры, которые вы предоставили.

l = [[1,2,3],[4,5,6]] 
flattened_l = [item for sublist in l for item in sublist] 
print flattened_l # prints [1,2,3,4,5,6] 

Для понимания списка начинаются в крайний левый для петли и работать ваш путь в. Переменная, элемент, в данном случае, является то, что будет добавлено.Он будет производить этот эквивалент:

l = [[1,2,3],[4,5,6]] 
flattened_l = [] 
for sublist in l: 
    for item in sublist: 
     flattened_l.append(item) 

Теперь за один последний

exactly_the_same_as_l = [item for item in sublist for sublist in l] 

Используя те же знания, мы можем создать цикл и посмотреть, как это будет behaveL

for item in sublist: 
    for sublist in l: 
     exactly_the_same_as_l.append(item) 

Теперь только причина, о которой говорилось выше, заключается в том, что когда был создан flattened_l, он также создал sublist. Это сводная причина, почему это не вызвало ошибку. Если вы запустили это без определения flattened_l, вы получите NameError

2

Петли for оцениваются слева направо. Любой list comprehension может быть переписан как цикл следующим образом:

l = [[1,2,3],[4,5,6]] 
flattened_l = [] 
for sublist in l: 
    for item in sublist: 
     flattened_l.append(item) 

выше правильный код для выпрямления списка, выбираете ли вы писать сжато как список понимание, или в этой расширенной версии ,

Второе понимание списка, которое вы написали, поднимет NameError, поскольку 'sublist' еще не определен. Вы можете увидеть это в письменном виде список понимания как цикл:

l = [[1,2,3],[4,5,6]] 
flattened_l = [] 
for item in sublist: 
    for sublist in l: 
     flattened_l.append(item) 

Единственной причиной, вы не видели ошибку, когда вы запускали ваш код потому, что вы ранее определенный подсписок при реализации вашего первого списка понимания.

Для получения дополнительной информации, вы можете зарегистрироваться Guido's tutorial on list comprehensions.

0

Обратите внимание, что вид понимания будет только «сгладить» список списков (или список других итераций). Также, если вы передадите ему список строк, вы «сгладите» его в список символов.

Чтобы обобщить это в значимом ключе, вы сначала хотите иметь возможность четко различать строки (или bytearrays) и другие типы последовательностей (или другие Iterables). Итак, давайте начнем с простой функцией:

import collections 
def non_str_seq(p): 
    '''p is putatively a sequence and not a string nor bytearray''' 
    return isinstance(p, collections.Iterable) and not (isinstance(p, str) or isinstance(p, bytearray)) 

С помощью этого мы можем построить рекурсивную функцию, чтобы сгладить любые

def flatten(s): 
    '''Recursively flatten any sequence of objects 
    ''' 
    results = list() 
    if non_str_seq(s): 
     for each in s: 
      results.extend(flatten(each)) 
    else: 
     results.append(s) 
    return results 

Есть, вероятно, более элегантные способы сделать это. Но это работает для всех встроенных типов Python, о которых я знаю. Простые объекты (числа, строки, экземпляры None, True, False все возвращаемые завернутые в список Словари возвращаются в виде списка ключей (в хэш порядке)

1

Для ленивого разработчика, который хочет быстрый ответ:..

>>> a = [[1,2], [3,4]] 
>>> [i for g in a for i in g] 
[1, 2, 3, 4] 
Смежные вопросы