Reputation: 85
I have three lists:
li1 = ["a", "a", "a", "a", "b", "b", "a", "a", "b"]
li2 = ["a", "a", "a", "b", "a,", "b", "a", "a"]
li3 = ["b", "b", "a", "a", "b"]
I want to "slice and paste" elements by "b"
The result is supposed to look like this:
li1 = ["aaaa", "b", "b", "aa", "b"]
li2 = ["aaa", "b", "a", "b", "aa"]
li3 = ["b", "b", "aa", "b"]
But I don't know how to approach this... please help me!
Upvotes: 4
Views: 218
Reputation: 11183
I'm late, but this is another option:
def join_in(lst, s):
res, append = [lst[0]], True
for i, e in enumerate(lst[1:]):
if res[-1][0] == s and e == s:
res[-1] += e
append = False
else: append = True
if append: res.append(e)
return res
Calling on the OP lists:
print (join_in(li1, 'a')) #=> ["aaaa", "b", "b", "aa", "b"]
print (join_in(li2, 'a')) #=> ["aaa", "b", "a", "b", "aa"]
print (join_in(li3, 'a')) #=> ["b", "b", "aa", "b"]
It is possible to call it on 'b'
:
print (join_in(join_in(li3, 'a'), 'b')) #=> ['bb', 'aa', 'b']
Upvotes: 0
Reputation: 5006
I don't get why all the answers look complicated for this. Did I miss something ?
li1 = ['a', 'a', 'a', 'b', 'b', 'a', 'a', 'b']
result = []
for e in li1:
if result and e != 'b' != result[-1]:
result[-1] += e
else:
result.append(e)
print(result)
Prints
['aaa', 'b', 'b', 'aa', 'b']
Keep it simple and stupid. Readability matters.
Upvotes: 1
Reputation: 78650
Use itertools.groupby
.
If you want to join groups not belonging to a certain key
from itertools import groupby
def join_except_key(iterable, key='b'):
groups = groupby(iterable)
for k, group in groups:
if k != key:
yield ''.join(group) # more general: ''.join(map(str, group))
else:
yield from group
Demo:
>>> li1 = ["a", "a", "a", "a", "b", "b", "a", "a", "b", "c", "c", "b", "c", "c"]
>>> list(join_except_key(li1))
['aaaa', 'b', 'b', 'aa', 'b', 'cc', 'b', 'cc']
If you want to join groups belonging to a certain key
from itertools import groupby
def join_by_key(iterable, key='a'):
groups = groupby(iterable)
for k, group in groups:
if k == key:
yield ''.join(group) # more general: ''.join(map(str, group))
else:
yield from group
Demo:
>>> li1 = ["a", "a", "a", "a", "b", "b", "a", "a", "b", "c", "c", "b", "c", "c"]
>>> list(join_by_key(li1))
['aaaa', 'b', 'b', 'aa', 'b', 'c', 'c', 'b', 'c', 'c']
Details on what groupby
produces (non generator approach for join_except_key
)
>>> li1 = ["a", "a", "a", "a", "b", "b", "a", "a", "b", "c", "c", "b", "c", "c"]
>>> groups = [(k, list(group)) for k, group in groupby(li1)]
>>> groups
[('a', ['a', 'a', 'a', 'a']),
('b', ['b', 'b']),
('a', ['a', 'a']),
('b', ['b']),
('c', ['c', 'c']),
('b', ['b']),
('c', ['c', 'c'])]
>>>
>>> result = []
>>> for k, group in groups:
...: if k != 'b':
...: result.append(''.join(group))
...: else:
...: result.extend(group)
...:
>>> result
['aaaa', 'b', 'b', 'aa', 'b', 'cc', 'b', 'cc']
The list comprehension groups = [...
in the second line was only needed for inspecting the elements of the grouping operation, it works fine with just groups = groupby(li1)
.
Upvotes: 5
Reputation: 489
Here is a function I wrote to perform this:
def Conbine(Li):
li=[]
li.append(Li[0])
Prev=Li[0]
for i in Li[1:]:
if not"b"in(i,Prev):li[-1]+=i
else:
Prev=i
li.append(i)
return li
Here is the result:
>>> Conbine(["a", "a", "a", "a", "b", "b", "a", "a", "b"])
['aaaa', 'b', 'b', 'aa', 'b']
>>> Conbine(["a", "a", "a", "b", "a,", "b", "a", "a"])
['aaa', 'b', 'a,', 'b', 'aa']
>>> Conbine(["b", "b", "a", "a", "b"])
['b', 'b', 'aa', 'b']
There are a lot of answers here already, but I hope this helped.
Upvotes: 1
Reputation: 164623
You can use itertools.groupby
, dividing logic into 3 parts:
groupby
key.itertools.chain.from_iterable
to flatten your iterable of lists.Here's a demonstration.
from itertools import chain, groupby
def sep_by_val(L, k='b'):
grouper = groupby(L, key=lambda x: x==k)
gen_of_lst = ([''.join(j)] if not i else list(j) for i, j in grouper)
return list(chain.from_iterable(gen_of_lst))
sep_by_val(li1) # ['aaaa', 'b', 'b', 'aa', 'b']
sep_by_val(li2) # ['aaa', 'b', 'a,', 'b', 'aa']
sep_by_val(li3) # ['b', 'b', 'aa', 'b']
Upvotes: 2
Reputation: 496
Itertools and Yield from are great python constructs but challenging to master. Something simpler would go like so involving string shifting and splitting.
result = []
while len(li1) > 0:
split = ''.join(li1).partition('b')
before, part, after = split
if before:
result.extend( before.split() )
if part:
result.append(part)
li1 = after.split()
print(result)
Upvotes: 1