如何使用itertools.zip_longest有效迭代以获取2个标记之间的数据

时间:2018-06-07 04:35:08

标签: python itertools

我有几个长列表,我想解析并获取感兴趣的数据。具体来说,我在一个列表中查找两种模式之间的数据,并使用相同的索引获取所有列表中的数据。我有以下字典,每个列表中包含大量数据(在此示例中仅显示少数数据):

 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 :(得分:0)

您可以使用dropwhiletakewhile

>>> 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)
但是,它并不是真的更快。

答案 1 :(得分:0)

以下是使用纯内置函数的示例:

<强>鉴于

 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中进行比较,因此您可以简单地定义一个谓词,其中&#34;接受所有行,其中第一项是从e到小于j&#34的字母;。为简洁起见,我们使用lambda来创建条件函数。我们可以轻松地将其重写为常规函数:

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

Re:效率

  • 简洁:与OP的9行相比,代码为2-3行。
  • 编码方式:除了您提供的谓词之外,没有硬编码查找。如果您打算重复使用此方法,请选择常规功能。此外,没有嵌套条件,易于阅读。
  • 速度:如果您计划多次查询数据,使用中间字典可以提高性能,从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的列表值具有相同的长度,则可以正常工作,如OP中所示。否则,请使用itertools.zip_longest