Как эффективно выполнять итерации с помощью itertools.zip_longest для захвата данных между 2 маркерами - PullRequest
0 голосов
/ 07 июня 2018

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

 LA = {
         'A':['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'], 
         'B':[ 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11], 
         'C':[ 21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32], 
         'D':[ 31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42], 
         'E':[..........................................................], 
         'F':[..........................................................]
      }

 for j in itertools.zip_longest(LA['A'], LA['B'], LA['C'], LA['D']):
     if (j[0] =='d'):
         grab_data = 1
     else:
        if not (j[0] == 'j'):
            grab_data = 1
        else:
          if (grab_data ==1):
             print ("My required Data", j)

Это напечатает следующее:

My required Data ('e', 4, 25, 35)
My required Data ('f', 5, 26, 36)
My required Data ('g', 6, 27, 37)
My required Data ('h', 7, 28, 38)
My required Data ('i', 8, 29, 39)

Это правильноно есть ли более эффективный и лаконичный способ сделать это?

Списки длинные и данных много.

Ответы [ 2 ]

0 голосов
/ 11 июня 2018

Вот пример использования чистых встроенных функций:

Дано

 data = {
     "A":["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"], 
     "B":[ 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11], 
     "C":[ 21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32], 
     "D":[ 31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42],
 }

pred = lambda x: (x[0] >= "e") and (x[0] < "j")

Код

transposed = list(zip(*data.values()))
revised = list(filter(pred, transposed))

Сейчаспечать:

for row in revised:
    print ("My required Data", row)

Вывод

My required Data ('e', 4, 25, 35)
My required Data ('f', 5, 26, 36)
My required Data ('g', 6, 27, 37)
My required Data ('h', 7, 28, 38)
My required Data ('i', 8, 29, 39)

Подробности

Легко транспонировать данные с пониманием,Вот результаты transposed:

[('a', 0, 21, 31),
 ('b', 1, 22, 32),
 ('c', 2, 23, 33),
 ('d', 3, 24, 34),
 ('e', 4, 25, 35),
 ('f', 5, 26, 36),
 ('g', 6, 27, 37),
 ('h', 7, 28, 38),
 ('i', 8, 29, 39),
 ('j', 9, 30, 40),
 ('k', 10, 31, 41),
 ('l', 11, 32, 42)]

Вы на полпути туда.Просто отфильтруйте результаты по условной функции (или pred icate) и напечатайте.

Re: предикаты

Поскольку строки можно сравнивать в Python, вы можете простоопределить предикат, который говорит: «принимать все строки, где первый элемент - это буква от e до меньше j».Для краткости мы используем lambda для создания условной функции.Мы можем легко переписать его как обычную функцию:

def pred(x):
    return (x[0] >= "e") and (x[0] < "j")

Re: эффективность

  • Для краткости: код состоит из 2-3 строк по сравнению с9 строк ОП.
  • Кодирование: нет никаких жестко закодированных поисков, кроме предиката, который вы предоставляете.Выберите регулярную функцию, если вы планируете использовать этот подход повторно.Кроме того, нет вложенных условных выражений и легко читается.
  • По скорости: если вы планируете многократно запрашивать данные, использование промежуточного диктанта должно повысить производительность, сократив поиск с O (n) до O (1) по времени.

Альтернативный пример:

# Using dictionaries
pred = lambda x: x >= "e" and x < "j"
transposed_dict = {x[0]: x[1:] for x in zip(*data.values())}
revised_dict = {k: v for k, v in transposed_dict.items() if pred(k)}

Допущения

Никаких дополнительных модулей не требуется при условии:

  • неупорядоченные данные: этот пример дает упорядоченные результаты в Python 3.6+.Если в младших версиях требуется порядок, убедитесь, что данные построены с collections.OrderedDict.
  • одинаковыми по размеру значениями: zip работает нормально, если вы знаете, что значения списка в dict имеют одинаковую длину, как видно изОП.В противном случае используйте itertools.zip_longest.
0 голосов
/ 07 июня 2018

Вы можете использовать dropwhile и takewhile:

>>> from itertools import zip_longest, takewhile, dropwhile
>>> 
>>> ABCD = zip_longest(*map(LA.__getitem__, 'ABCD'))
>>> ABCD = dropwhile(lambda j: j[0] != 'd', ABCD)
>>> _ = next(ABCD)
>>> for j in takewhile(lambda j: j[0] != 'j', ABCD):
...     print("My required data", j)
... 
My required data ('e', 4, 25, 35)
My required data ('f', 5, 26, 36)
My required data ('g', 6, 27, 37)
My required data ('h', 7, 28, 38)
My required data ('i', 8, 29, 39)

Хотя на самом деле это не так быстро.

...