簡體   English   中英

將元組列表中的一系列條目提取到子列表中的優雅方法是什么?

[英]What's an elegant way to extract a series of entries in a list of tuples into sublists?

假設我在這樣的元組列表中有一系列條目:

TRUE = 1
listOfTuples = [('selectable', 'frequency'), ('color', 'green'), ('item', '10 Hz'), 
                ('value', 10), ('align', 'left'), ('hidden', TRUE), ('item', '20 Hz'), 
                ('value', 20), ('align', 'right'), ('item', '50 Hz'), ('value', 50), 
                ('item', '100 Hz'), ('value', 100), ('textColor', 0xFF0000)]

現在我想提取一個包含單個項目條目的列表,如下所示:

[(('item', '10 Hz'), ('value', 10), ('align', 'left'), ('hidden', TRUE)),
 (('item', '20 Hz'), ('value', 20), ('align', 'right')),
 (('item', '50 Hz'), ('value', 50)), 
 (('item', '100 Hz'), ('value', 100), ('textColor', '0xFF0000'))]

標識子列表的定界關鍵字始終是item或列表末尾。 兩個相鄰的分隔符之間可以有任意數量的元組。 item第一次出現之前的列表內容將被忽略。 關鍵字item的檢測應該不區分大小寫。

我不是 Python 愛好者,所以我不知道如何應用列表理解之類的東西(如果這真的可能的話),因為我需要在定界符之間提取列表。 當然,我可以通過遍歷列表、識別關鍵字在元組中的位置然后提取子列表來以行人方式完成,但我希望有一個更優雅的解決方案。

您可以使用itertools.groupby來完成任務:

from itertools import accumulate, groupby

TRUE = 1
listOfTuples = [
    ("selectable", "frequency"),
    ("color", "green"),
    ("item", "10 Hz"),
    ("value", 10),
    ("align", "left"),
    ("hidden", TRUE),
    ("item", "20 Hz"),
    ("value", 20),
    ("align", "right"),
    ("item", "50 Hz"),
    ("value", 50),
    ("item", "100 Hz"),
    ("value", 100),
    ("textColor", 0xFF0000),
]


a = accumulate(t == "item" for t, *_ in listOfTuples)

out = []
for _, g in groupby(zip(a, listOfTuples), lambda k: k[0]):
    l = tuple(t for _, t in g)
    if l[0][0] == "item":
        out.append(l)

print(out)

印刷:

[
    (("item", "10 Hz"), ("value", 10), ("align", "left"), ("hidden", 1)),
    (("item", "20 Hz"), ("value", 20), ("align", "right")),
    (("item", "50 Hz"), ("value", 50)),
    (("item", "100 Hz"), ("value", 100), ("textColor", 16711680)),
]

您可以使用tuple() function 將列表轉換為元組,這樣您就可以將 append listOfTuples變量中的所有元組轉換為您需要的 output:

TRUE = 1
lot = [('selectable', 'frequency'), ('color', 'green'), ('item', '10 Hz'), 
                ('value', 10), ('align', 'left'), ('hidden', TRUE), ('item', '20 Hz'), 
                ('value', 20), ('align', 'right'), ('item', '50 Hz'), ('value', 50), 
                ('item', '100 Hz'), ('value', 100), ('textColor', 0xFF0000)]

l = [[]]
for i in lot:
    if i[0]=='item':
        l[-1] = tuple(l[-1])
        l.append([])
    l[-1].append(i)
print(l[1:])

Output:

[(('item', '10 Hz'), ('value', 10), ('align', 'left'), ('hidden', 1)), (('item', '20 Hz'), ('value', 20), ('align', 'right')), (('item', '50 Hz'), ('value', 50)), [('item', '100 Hz'), ('value', 100), ('textColor', 16711680)]]

這種方法唯一的缺點是需要刪除 output 元組列表的第一個元素,因此在某些情況下它可能不起作用。

好的,所以與此同時,我了解了更多關於列表理解、 _*和 for 循環中多個索引的使用。 此外,一位好朋友提出了以下解決方案:

indices = [i for i, value in enumerate(listOfTuples) 
           if value[0].casefold() == "item"] + [len(listOfTuples)]
out = [listOfTuples[i:j] for i,j in zip(indices[:-1], indices[1:])]

Indices包含所有出現的item和列表中最后一項的索引。 以移位的方式使用indices ( zip(indices[:-1], indices[1:]) ) 允許直接構建out

一種沒有條件的建設性方法。 使用itertools.groupby'item'分組。 分組是一個 True/False 分類過程(理想情況下會引發 True/False 值的交替序列! ),因此您可以按 2 個塊進行切片並將它們鏈接在一起。

右拆分( initial )條件意味着在“右邊”找到第一個帶有item的組,並且可以忘記“左邊”的內容( [1:] -部分)。

import itertools as it

listOfTuples = # see question

# group by item & discard 1st group due to split-right condition
lst = tuple(tuple(grps) for _, grps in it.groupby(listOfTuples, lambda p: p[0] == 'item'))[1:]

# chain the slices
lst_new = [tuple(it.chain.from_iterable(lst[2*i:2*(i+1)])) for i in range(len(lst)//2)]

print(lst_new)

相同的想法,但有發電機

...

lst = (tuple(grps) for _, grps in it.groupby(listOfTuples, lambda p: p[0] == 'item'))
next(l) # split-right initial condition
l1, l2 = it.tee(lst)
n = len(tuple(l2))

lst_new = [tuple(it.chain.from_iterable(it.islice(l1, 0, 2, None))) for _ in range(n//2)]

一種(邏輯上不同的)基於索引的方法

...
# indices of the items
iter_ = filter(None, (tuple(grps)[0][0] if check else None for check, grps in it.groupby(enumerate(listOfTuples), lambda p: p[1][0] == 'item')))
# zip-stuffs
it1, it2 = it.tee(iter_)
next(it2)
it2 = it.chain(it2, iter((len(listOfTuples),)))
# apply the slices and cast to tuples
lst_new = list(map(tuple, map(listOfTuples.__getitem__, it.starmap(slice, zip(it1, it2)))))

print(lst_new)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM