【问题标题】:Tokenize a list标记列表
【发布时间】:2020-03-31 09:49:03
【问题描述】:

我喜欢使用列表项作为分隔符来标记列表。

有没有一种pythonic方法可以做到这一点,还是我必须自己写一些东西。

Data=['Label',23,'NORM','|','RESP',1.256,None,'|','','','|','RELV','','']
SubList = TokenizeList (Data,Delim='|')

打印 SubList 会导致

[ ['Label',23,'NORM'] , ['RESP',1.256,None] , ['',''] , ['RELV','',''] ]

【问题讨论】:

  • 这些词可以包含任何字符吗?
  • 您是指分隔符还是列表项?原始列表可以包含任何内容,分隔符是 .split() 中的字符
  • 我的意思是物品。例如,它们可以包含空格吗?
  • 是的,他们可能可以,但是一个空格(或多个空格)在这里就像一个空字符串,所以我可以提前替换它们
  • 这能回答你的问题吗? Python splitting a list based on a delimiter word

标签: python python-3.x


【解决方案1】:

是的,你可以使用itertools.groupby

>>> from itertools import groupby
>>> Data=['Label',23,'NORM','|','RESP',1.256,None,'|','','','|','RELV','','']
>>> [list(g) for k,g in groupby(Data,key=lambda x:x == '|') if not k]
[['Label', 23, 'NORM'], ['RESP', 1.256, None], ['', ''], ['RELV', '', '']]

你当然可以做一个函数:

def splitList(sequence, delimiter):
    return [list(g) for k, g in groupby(sequence, key = lambda x: x == delimiter) if not k]
>>> splitList(sequence = Data, delimiter = '|')
[['Label', 23, 'NORM'], ['RESP', 1.256, None], ['', ''], ['RELV', '', '']]

【讨论】:

  • 这个答案应该被接受,因为它是唯一真正pythonic的答案,正如用户所要求的那样
  • 虽然您可以为此使用itertools.groupby(),但这可能不是最有效的方法
  • 如果找到两个连续的分隔符,它的行为也会不同(而且很难适应)。
【解决方案2】:

试试这个:

def group_by_sep(items, sep='|'):
    inner_list = []
    for item in items:
        if item == sep:
            yield inner_list
            inner_list = []
        else:
            inner_list.append(item)
    if inner_list:
        yield inner_list


Data=['Label',23,'NORM','|','RESP',1.256,None,'|','','','|','RELV','','','|','|','now','|']

SubList = list(group_by_sep(Data, '|'))
print(SubList)
# [['Label', 23, 'NORM'], ['RESP', 1.256, None], ['', ''], ['RELV', '', ''], [], ['now']]

请注意,此处可以使用itertools.groupby 方法,但它不等同于上述方法,并且对确切行为的控制较少:

import itertools


def group_by_sep2(items, sep='|'):
    yield from (
        list(g)
        for k, g in itertools.groupby(items, key=lambda x: x == sep)
        if not k)


SubList2 = list(group_by_sep2(Data, '|'))
print(SubList2)
# [['Label', 23, 'NORM'], ['RESP', 1.256, None], ['', ''], ['RELV', '', ''], ['now']]

在两个连续的分隔符之间缺少空的list

另外,它不如上面的直接方法有效:

%timeit list(group_by_sep(Data))
# 1000 loops, best of 3: 1.47 µs per loop
%timeit list(group_by_sep2(Data))
# 100 loops, best of 3: 4.01 µs per loop

%timeit list(group_by_sep(Data * 1000))
# 1000 loops, best of 3: 1.33 ms per loop
%timeit list(group_by_sep2(Data * 1000))
# 100 loops, best of 3: 2.83 ms per loop

%timeit list(group_by_sep(Data * 1000000))
# 1000 loops, best of 3: 1.67 s per loop
%timeit list(group_by_sep2(Data * 1000000))
# 100 loops, best of 3: 3.22 s per loop

基准测试表明直接方法的速度快了 ~2 到 ~3 倍。

(已编辑以将其全部编写为生成器并包含更多边缘情况)

【讨论】:

  • 嘿,我们都认为相同的逻辑;-)
  • @shaikmoeed 没有什么可以写的来解决这个问题 ;-)
  • 我们的方法符合zen of python 规则之一,即显式优于隐式。 (+1) 用于添加时间。
【解决方案3】:

试试这个,简单直接(Pythonic),

def tokenize_list(array, sep='|'):
    result = []
    _temp = []
    for el in array:
        if el == sep:
            result.append(_temp)
            _temp = []
        else:
            _temp.append(el)
    if _temp: # Finally append list after for-loop, to store last vlaues present in _temp if exists.
        result.append(_temp) 
    return result

输出:

>>> data = ['Label',23,'NORM','|','RESP',1.256,None,'|','','','|','RELV','','', '|']
>>> tokenize_list(data)
[['Label', 23, 'NORM'], ['RESP', 1.256, None], ['', ''], ['RELV', '', '']]

【讨论】:

  • 如果Data| 结尾,这将无法正常工作(添加最后一个内部list 两次)
  • @norok2 谢谢。编辑了答案,以处理这种情况。
猜你喜欢
  • 2018-07-18
  • 2010-12-31
  • 1970-01-01
  • 1970-01-01
  • 2013-06-19
  • 2014-03-18
  • 2021-12-28
  • 2019-08-07
  • 2018-07-06
相关资源
最近更新 更多