我已经进行了广泛的搜索,不幸的是有点磕磕绊绊。我希望能够获取一个列表(或字符串,或任何可迭代的),并能够将其拆分为其唯一的子组。我提出或找到的解决方案都不是非常整洁。
以下是我想要做的一个例子:
'122333444455555'
→['1', '22', '333', '4444', '55555']
请注意,我不想删除任何已经出现的组。例如,使用以下输入'AAABBBAAA'
我仍然希望['AAA', 'BBB', 'AAA']
作为输出。基本上,我想要一个包含子组的数组,每个子组只包含相同的元素。如果你要扁平化这个数组,那么你就可以获得原始列表(我希望这不会太令人困惑,而且这些例子有助于解释我在寻找什么)。
下面,我有我的这个问题的解决方案版本,但我觉得它太笨重了。我几乎100%确定有一些内置函数可以让这个问题得到非常优雅的解决,毕竟这是Python。我想要注意的是,因为这不是特定于字符串的,所以正则表达式不合适(虽然看起来仍然是一个很好的奖励!)。
def split_by_unique_groups(list_):
to_return = []
idx = 0
while idx != len(list_):
curr = list_[idx]
next_bad_idx = None
for x in range(idx+1, len(list_)):
if list_[x] != curr:
next_bad_idx = x
break
sub_str = list_[idx:next_bad_idx] # [x:None] returns x to len(s)
to_return.append(sub_str)
if next_bad_idx is None:
break
idx = next_bad_idx
return to_return
我对这段代码的最大问题是我很难找到一个很好的方法来查找列表中指向不同项目的下一个索引。例如,在字符串' AAABBB'中,索引(0,2)和(3,5)表示唯一项目组周围的边界。
我认为使这段代码更简洁的一个关键方法是能够有一种从索引0到索引2或从索引3到索引5的好方法。我的意思是如果它更简洁,如果有一种更好的方法可以找到列表中与当前项目不同的下一项。
答案 0 :(得分:1)
如果你没有这个"省略重复"要求,可以在一行(+导入)中完成:
import itertools
["".join(v) for _,v in itertools.groupby('122333444455555')]
编辑:问题编辑完毕后,这个"省略重复"要求变成"保持重复"所以答案可以在这里停止(或者只是消失并关闭)。但是"避免重复"事情也很有趣所以我把它留在。
但是,如果您在字符串末尾添加1
,则会1
两次。
如果您不想保留订单,请执行设置理解:
{"".join(v) for _,v in itertools.groupby('122333444455555')}
如果你想保留订单,它会稍微复杂一些。我使用set
来记下已经发生的项目:
import itertools
s = '1223334444555551'
result = []
aux=set()
for x in ("".join(v) for _,v in itertools.groupby(s)):
if not x in aux:
aux.add(x)
result.append(x)
print(result)
结果:
['1', '22', '333', '4444', '55555']
现在如果你想删除重复数据,即使数字位数不同,也只是一个小的变化,保留组密钥并在aux
集中使用它:
s = '12233344445555511'
result = []
aux=set()
for k,x in ((k,"".join(v)) for k,v in itertools.groupby(s)):
if not k in aux:
aux.add(x)
result.append(x)
最后一个11
组被丢弃。