Кортежи в списке массивов в python [duplicate]

Мне нравится анализировать HTML с регулярными выражениями. Я не пытаюсь разбирать идиот HTML, который намеренно нарушен. Этот код является моим основным парсером (версия Perl):

$_ = join "",; tr/\n\r \t/ /s; s//>\n/g; s/\n ?\n/\n/g;
s/^ ?\n//s; s/ $//s; print

Он называется htmlsplit, разбивает HTML на строки, с одним тегом или фрагментом текста в каждой строке. Затем линии могут быть обработаны другими текстовыми инструментами и сценариями, такими как grep , sed , Perl и т. Д. Я даже не шучу :) Наслаждайтесь.

Достаточно просто переписать мой скрипт Perl-all-first Perl в приятную поточную вещь, если вы хотите обрабатывать огромные веб-страницы. Но это действительно не обязательно.

Бьюсь об заклад, я заберусь для этого.

HTML Split


Против моего ожидая, что это получило некоторые upvotes, поэтому я предлагаю несколько правильных выражений:

/(<.*?>|[^<]+)\s*/g    # get tags and text
/(\w+)="(.*?)"/g       # get attibutes

Они хороши для XML / XHTML.

С небольшими вариациями он может справиться с беспорядочным HTML ... или сначала конвертировать HTML -> XHTML.


Лучший способ записи регулярных выражений - в Lex / Yacc стиль, а не непрозрачные однострочные или прокомментированные многострочные чудовища. Я не делал этого здесь; эти им едва ли нужны.

374
задан martineau 14 January 2017 в 17:53
поделиться

9 ответов

zip является его собственным обратным! Если вы используете специальный оператор *.

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

Как это работает, вызывая zip с аргументами:

zip(('a', 1), ('b', 2), ('c', 3), ('d', 4))

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

599
ответ дан Patrick 15 August 2018 в 22:15
поделиться
  • 1
    О, если бы это было так просто. Распаковка zip([], []) таким образом не дает вам [], []. Это дает вам []. Если только... – user2357112 24 February 2014 в 14:06
  • 2
    @cdhagmann: Теперь попробуйте это с помощью list1=[]; list2=[]. – user2357112 26 February 2014 в 04:53
  • 3
    Это не работает в Python3. См. stackoverflow.com/questions/24590614/… – Tommy 5 July 2014 в 22:35
  • 4
    @Tommy Это неверно. zip работает точно так же в Python 3, за исключением того, что он возвращает итератор вместо списка. Чтобы получить тот же результат, что и выше, вам просто нужно обернуть zip-вызов в списке: list(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])) выведет [('a', 'b', 'c', 'd'), (1, 2, 3, 4)] – MJeffryes 11 March 2015 в 15:11
  • 5
    Обратите внимание: вы можете встретить проблемы памяти и производительности с очень длинными списками. – Laurent LAPORTE 14 October 2016 в 12:44

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

result = ([ a for a,b in original ], [ b for a,b in original ])

Он должен масштабироваться лучше. Особенно, если Python делает все возможное, чтобы не расширять списки, если это не нужно.

(Кстати, это делает 2-кортежи (пары) списков, а не список кортежей, например zip).

Если генераторы вместо фактических списков в порядке, это будет делать следующее:

result = (( a for a,b in original ), ( b for a,b in original ))

Генераторы не пробиваются по списку, пока вы не спросите об каждом элементе, но на с другой стороны, они сохраняют ссылки на исходный список.

25
ответ дан Anders Eurenius 15 August 2018 в 22:15
поделиться
  • 1
    «Особенно, если Python делает все возможное, чтобы не расширять списки, если это не требуется». mmm ... нормально, списки размножаются сразу же - или я что-то не так понял? – glglgl 15 August 2011 в 20:52
  • 2
    @glglgl: Нет, ты, наверное, прав. Я просто надеялся, что какая-то будущая версия может начать поступать правильно. (Невозможно изменить, семантика побочных эффектов, которые нуждаются в изменениях, вероятно, уже разочарована.) – Anders Eurenius 15 October 2012 в 13:54
  • 3
    То, что вы надеетесь получить, - это экспрессия генератора, которая уже существует. – glglgl 15 October 2012 в 14:12
  • 4
    Это не «масштабируется лучше», чем версия zip(*x). zip(*x) требуется только один проход через цикл и не использует элементы стека. – habnabit 17 November 2013 в 18:38
  • 5
    Является ли оно «более масштабируемым»? или не зависит от жизненного цикла исходных данных по сравнению с транспонированными данными. Этот ответ лучше, чем использование zip, если прецедентом является то, что транспонированные данные используются и отбрасываются немедленно, в то время как исходные списки остаются в памяти намного дольше. – Ekevoo 15 November 2015 в 07:55

Если у вас есть списки, которые не имеют одинаковой длины, вы можете не захотеть использовать zip в соответствии с ответом Patricks. Это работает:

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

Но с разными списками длины zip обрезает каждый элемент до длины кратчайшего списка:

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e')]

Вы можете использовать карту без функции для заполнения пустые результаты с None:

>>> map(None, *[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e'), (1, 2, 3, 4, None)]

zip () немного быстрее, хотя.

19
ответ дан Chris 15 August 2018 в 22:15
поделиться
  • 1
    интересно, можете ли вы объяснить, как map работает так? – Grijesh Chauhan 26 September 2013 в 16:53
  • 2
    Вы также можете использовать izip_longest – Marcin 26 September 2013 в 17:52
  • 3
    Известен как zip_longest для пользователей python3. – zezollo 8 March 2016 в 10:02
  • 4
    @GrijeshChauhan Я знаю, что это действительно старо, но это странная встроенная функция: docs.python.org/2/library/functions.html#map & quot; Если функция None, то функция идентификации предполагается; Если существует несколько аргументов, map () возвращает список, состоящий из кортежей, содержащих соответствующие элементы, из всех итераций (своего рода операция транспонирования). Итерируемыми аргументами могут быть последовательность или любой итерируемый объект; результатом всегда является список. & quot; – cactus1 14 July 2017 в 19:26
  • 5
    @ cactus1 Спасибо, полезно, что я изучал Python – Grijesh Chauhan 15 July 2017 в 04:42

Это только другой способ сделать это, но это очень помогло мне написать здесь:

Наличие этой структуры данных:

X=[1,2,3,4]
Y=['a','b','c','d']
XY=zip(X,Y)

Результат:

In: XY
Out: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]

Чем больше pythonic способ распаковать его и вернуться к оригиналу, это, на мой взгляд, это:

x,y=zip(*XY)

Но это возвращает кортеж, поэтому, если вам нужен массив, вы можете использование:

xy=(list(x),list(y))
2
ответ дан G M 15 August 2018 в 22:15
поделиться

Так вы можете транспонировать кортеж 2x4 в кортеж 4x2.

 >>> tuple(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])) 
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
0
ответ дан helcode 15 August 2018 в 22:15
поделиться

Еще один способ подумать о unzip или transpose - преобразовать список строк в список столбцов.

pitchers = [('Nolan', 'Ryan'), ('Roger', 'Clements'), ('Schilling','Curt')]
first_names, last_names = zip(*pitchers)
In [45]: first_names
Out[45]: ('Nolan', 'Roger', 'Schilling')
In [46]: last_names
Out[46]: ('Ryan', 'Clements', 'Curt')
0
ответ дан JawSaw 15 August 2018 в 22:15
поделиться
>>> original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> tuple([list(tup) for tup in zip(*original)])
(['a', 'b', 'c', 'd'], [1, 2, 3, 4])

Дает кортеж списков, как в вопросе.

list1, list2 = [list(tup) for tup in zip(*original)]

Распаковывает два списка.

9
ответ дан Noyer282 15 August 2018 в 22:15
поделиться

Мне нравится использовать zip(*iterable) (который является частью кода, который вы ищете) в моих программах:

def unzip(iterable):
    return zip(*iterable)

Я нахожу unzip более читаемым.

12
ответ дан wassimans 15 August 2018 в 22:15
поделиться

Поскольку он возвращает кортежи (и может использовать тонны памяти), трюк zip(*zipped) кажется мне более умным, чем полезным.

Вот функция, которая на самом деле даст вам обратный zip.

def unzip(zipped):
    """Inverse of built-in zip function.
    Args:
        zipped: a list of tuples

    Returns:
        a tuple of lists

    Example:
        a = [1, 2, 3]
        b = [4, 5, 6]
        zipped = list(zip(a, b))

        assert zipped == [(1, 4), (2, 5), (3, 6)]

        unzipped = unzip(zipped)

        assert unzipped == ([1, 2, 3], [4, 5, 6])

    """

    unzipped = ()
    if len(zipped) == 0:
        return unzipped

    dim = len(zipped[0])

    for i in range(dim):
        unzipped = unzipped + ([tup[i] for tup in zipped], )

    return unzipped
1
ответ дан Waylon Flinn 15 August 2018 в 22:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: