用最Pythonic的方法按重复元素拆分数组
我有一个物品列表,想要根据一个分隔符来拆分这个列表。我希望所有的分隔符都被去掉,并且在分隔符出现两次的时候进行拆分。例如,如果分隔符是'X'
,那么下面这个列表:
['a', 'b', 'X', 'X', 'c', 'd', 'X', 'X', 'f', 'X', 'g']
会变成:
[['a', 'b'], ['c', 'd'], ['f', 'g']]
注意最后一组没有被拆分。
我写了一些不太好看的代码来实现这个功能,但我相信一定有更好的方法。如果你能设置一个任意长度的分隔符(也就是说,在看到N个分隔符后进行拆分),那就更棒了。
11 个回答
4
使用生成器函数来保持你在列表中迭代器的状态,以及到目前为止看到的分隔符字符的数量:
l = ['a', 'b', 'X', 'X', 'c', 'd', 'X', 'X', 'f', 'X', 'g']
def splitOn(ll, x, n):
cur = []
splitcount = 0
for c in ll:
if c == x:
splitcount += 1
if splitcount == n:
yield cur
cur = []
splitcount = 0
else:
cur.append(c)
splitcount = 0
yield cur
print list(splitOn(l, 'X', 2))
print list(splitOn(l, 'X', 1))
print list(splitOn(l, 'X', 3))
l += ['X','X']
print list(splitOn(l, 'X', 2))
print list(splitOn(l, 'X', 1))
print list(splitOn(l, 'X', 3))
输出结果是:
[['a', 'b'], ['c', 'd'], ['f', 'g']]
[['a', 'b'], [], ['c', 'd'], [], ['f'], ['g']]
[['a', 'b', 'c', 'd', 'f', 'g']]
[['a', 'b'], ['c', 'd'], ['f', 'g'], []]
[['a', 'b'], [], ['c', 'd'], [], ['f'], ['g'], [], []]
[['a', 'b', 'c', 'd', 'f', 'g']]
编辑:我也很喜欢使用groupby,这里是我的尝试:
from itertools import groupby
def splitOn(ll, x, n):
cur = []
for isdelim,grp in groupby(ll, key=lambda c:c==x):
if isdelim:
nn = sum(1 for c in grp)
while nn >= n:
yield cur
cur = []
nn -= n
else:
cur.extend(grp)
yield cur
这和我之前的回答差不多,只是让groupby来处理输入列表的迭代,创建匹配分隔符和不匹配分隔符的字符组。那些不匹配的字符会被添加到当前元素中,而匹配的字符组则负责分隔出新的元素。对于很长的列表来说,这种方法可能更高效,因为groupby的处理是在C语言中完成的,并且只需遍历列表一次。
4
这里有一种方法可以使用 itertools.groupby()
来实现:
import itertools
class MultiDelimiterKeyCallable(object):
def __init__(self, delimiter, num_wanted=1):
self.delimiter = delimiter
self.num_wanted = num_wanted
self.num_found = 0
def __call__(self, value):
if value == self.delimiter:
self.num_found += 1
if self.num_found >= self.num_wanted:
self.num_found = 0
return True
else:
self.num_found = 0
def split_multi_delimiter(items, delimiter, num_wanted):
keyfunc = MultiDelimiterKeyCallable(delimiter, num_wanted)
return (list(item
for item in group
if item != delimiter)
for key, group in itertools.groupby(items, keyfunc)
if not key)
items = ['a', 'b', 'X', 'X', 'c', 'd', 'X', 'X', 'f', 'X', 'g']
print list(split_multi_delimiter(items, "X", 2))
我得说,cobbal 的解决方案要简单得多,但结果是一样的。
13
我觉得这个问题可能没有什么特别优雅的解决办法(当然我希望我错了),所以我建议用一种简单直接的方法:
def nSplit(lst, delim, count=2):
output = [[]]
delimCount = 0
for item in lst:
if item == delim:
delimCount += 1
elif delimCount >= count:
output.append([item])
delimCount = 0
else:
output[-1].append(item)
delimCount = 0
return output
>>> nSplit(['a', 'b', 'X', 'X', 'c', 'd', 'X', 'X', 'f', 'X', 'g'], 'X', 2)
[['a', 'b'], ['c', 'd'], ['f', 'g']]