2

I want to combine two elements in a list based on a given condition.

For example if I encounter the character 'a' in a list, I would like to combine it with the next element. The list:

['a', 'b', 'c', 'a', 'd']

becomes

['ab', 'c', 'ad']

Is there any quick way to do this?

One solution I have thought of is to create a new empty list and iterate through the first list. As we encounter the element 'a' in list 1, we join list1[index of a] and list1[index of a + 1] and append the result to list 2. However I wanted to know if there is any way to do it without creating a new list and copying values into it.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Arat254
  • 449
  • 2
  • 5
  • 17

6 Answers6

4

This does not create a new list, just modifies the existing one.

l = ['a', 'b', 'c', 'a', 'd']
for i in range(len(l)-2, -1, -1):
    if l[i] == 'a':
        l[i] = l[i] + l.pop(i+1)
print(l)
EyuelDK
  • 3,029
  • 2
  • 19
  • 27
3

If you don't want to use list comprehension to create a new list (maybe because your input list is huge) you could modify the list in-place:

i=0
while i < len(l):
 if l[i]=='a':
  l[i] += l.pop(i+1)
  i += 1
MassPikeMike
  • 672
  • 3
  • 12
2

Use a list comprehension with an iterator on your list. When the current iteratee is a simply join it with the next item from the iterator using next:

l = ['a', 'b', 'c', 'a', 'd']

it = iter(l)
l[:] =  [i+next(it) if i == 'a' else i for i in it]
print l
# ['ab', 'c', 'ad']
Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139
  • List comprehension is creating a new list, thus contradicting with the user's requirements `without creating a new list ` – EyuelDK Apr 26 '17 at 15:06
  • @EyuelDK Well about a full slice assignment to the original list? – Moses Koledoye Apr 26 '17 at 15:08
  • It Still creates a new list, but you just reassigned the elements to the slice. It still does not modify in place. To summarize, if you are using a list comprehension, it is creating a new list. – EyuelDK Apr 26 '17 at 15:10
  • @EyuelDK Depends on what create a new list really means in this context. The `range` you've used in your solution creates a new list in Python 2. – Moses Koledoye Apr 26 '17 at 15:15
  • You are right, in python 2.7 but I think that isn't relevant for this problem. It is implied that the user didn't want to create a new list of the original list, my use of range is irrelevant - can be fixed by using Python 3 or just a while statement, it isn't an issue. But what you are doing is creating a new list and then reassigning to the original list - just in a fancy syntax. That's why I think it doesn't meet requirement. – EyuelDK Apr 26 '17 at 15:18
0

Well, if you don't want to create a new list so much, here we go:

from itertools import islice

a = list("abcdabdbac")

i = 0
for x, y in zip(a, islice(a, 1, None)):
    if x == 'a':
        a[i] = x + y
        i += 1
    elif y != 'a':
        a[i] = y
        i += 1

try:
    del a[i:]
except:
    pass
ForceBru
  • 43,482
  • 10
  • 63
  • 98
0

you could use itertools.groupby and group by:

  • letter follows a or
  • letter is not a

using enumerate to generate the current index, which allows to fetch the previous element from the list (creating a new list but one-liner)

import itertools

l = ['a', 'b', 'c', 'a', 'd']

print(["".join(x[1] for x in v) for _,v in itertools.groupby(enumerate(l),key=lambda t: (t[0] > 0 and l[t[0]-1]=='a') or t[1]=='a')])

result:

['ab', 'c', 'ad']
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
-1

This is easy way. Mb not pythonic way.

l1 = ['a', 'b', 'c', 'a', 'd']

do_combine = False
combine_element = None
for el in l1:
    if do_combine:
        indx = l1.index(el)
        l1[indx] = combine_element + el 
        do_combine = False
        l1.remove(combine_element)
    if el == 'a':
        combine_element = el
        do_combine = True

print(l1)
    # ['ab', 'c', 'ad']
dikkini
  • 1,184
  • 1
  • 23
  • 52