tmthyjames
tmthyjames

Reputation: 1605

Combine elements of lists if some condition

How do I combine the elements of a list if some condition is met.

I've seen posts about combining elements of a list, but not with some condition.

Say I have a list containing lists of words:

words = [
    ['this','that!','riff','raff'],
    ['hip','hop!','flip!','flop'],
    ['humpty','dumpty!','professor!','grumpy!']
]

How do I combine only those elements that contain an !?

For example, the output would look like this:

[['this', 'that!', 'riff', 'raff'],
 ['hip', 'hop!, flip!', 'flop'],  # 1,2 are now combined
 ['humpty', 'dumpty!, professor!, grumpy!']]   # 1,2,3 are now combined

I tried this:

for word in words:
    word = ', '.join(i for i in word if re.search('!',str(i)))
    print word

but got:

that!
hop!, flip!
dumpty!, professor!, grumpy!

Thank you.

Upvotes: 8

Views: 3329

Answers (3)

Padraic Cunningham
Padraic Cunningham

Reputation: 180391

result = []

for sub_lst in words:
    result.append([])
    temp = ""
    for ele in sub_lst:
        if not temp and not "!" in ele:
            result[-1].append(ele)
        elif temp and not "!" in ele:
            result[-1].append(temp)
            result[-1].append(ele)
            temp = ""
        else:
            temp += "," + ele if temp else ele
    if temp:
        result[-1].append(temp)
 [['this', 'that!', 'riff', 'raff'], ['humpty', 'dumpty!,professor!,grumpy!'], ['hip', 'hop!,flip!', 'flop']]

If you want all words with a ! to be joined including words separated by words that don't contain a ! i.e ['humpty', 'dumpty!', 'professor!', 'grumpy!',"foo","bar!"] would become ['humpty', 'foo', 'dumpty!,professor!,grumpy!,bar!']:

result = []
for sub_l in words:
    result.append([])
    temp = ""
    for word in sub_l:
        if "!" in word:
            temp += "," + word if temp else word
        else:
            result[-1].append(word)
    result[-1].append(temp)

Some timings show @vikramls is the most efficient and the itertools solution is the least efficient.:

In [31]: %%timeit
   ....: result = []
   ....: for sub_lst in words:
   ....:     result.append([])
   ....:     temp = ""
   ....:     for ele in sub_lst:
   ....:         if not temp and not "!" in ele:
   ....:             result[-1].append(ele)
   ....:         elif temp and not "!" in ele:
   ....:             result[-1].append(temp)
   ....:             result[-1].append(ele)
   ....:             temp = ""
   ....:         else:
   ....:             temp += "," + ele if temp else ele
   ....:     if temp:
   ....:         result[-1].append(temp)
   ....: 
100000 loops, best of 3: 16 µs per loop

In [32]: %%timeit
output = []
for wl in words:
    out_wl = []
    bang_wl = []
    for w in wl:
        if '!' in w:                   
            bang_wl.append(w)
        else:                        
            if bang_wl:
                out_wl.append(','.join(bang_wl))
                bang_wl = []
            out_wl.append(w)
    if bang_wl:                               
        out_wl.append(','.join(bang_wl))
    output.append(out_wl)
   ....: 
100000 loops, best of 3: 15.2 µs per loop

In [33]: %%timeit
out = []
>>> for lst in words:
    d = []
    for k, g in groupby(lst, lambda x: '!' in x):
        if k:
            d.append(', '.join(g))
        else:                     
            d.extend(g)
    out.append(d)
   ....: 
10000 loops, best of 3: 48.1 µs per loop

If you just want the words ending with an !:

In [34]: %%timeit
result = []
for sub_lst in words:
    result.append([])
    temp = ""                              
    for ele in sub_lst:
        if not temp and not ele[-1] == "!":
            result[-1].append(ele)
        elif temp and not ele[-1] == "!":
            result[-1].append(temp)
            result[-1].append(ele)
            temp = ""
        else:               
            temp += "," + ele if temp else ele
    if temp:                            
        result[-1].append(temp)
   ....: 
100000 loops, best of 3: 17 µs per loop

Upvotes: 1

vikramls
vikramls

Reputation: 1822

Here's my solution:

words = [
    ['this','that!','riff','raff'],
    ['hip','hop!','flip!','flop'],
    ['humpty','dumpty!','professor!','grumpy!']
]

output = []
for wl in words:
    out_wl = []
    bang_wl = []
    for w in wl:
        if '!' in w:
            bang_wl.append(w)
        else:
            if bang_wl:
                out_wl.append(','.join(bang_wl))
                bang_wl = []
            out_wl.append(w)
    if bang_wl:
        out_wl.append(','.join(bang_wl))
    output.append(out_wl)

print output

Output:

[['this', 'that!', 'riff', 'raff'], ['hip', 'hop!,flip!', 'flop'], ['humpty', 'dumpty!,professor!,grumpy!']]

bang_wl accumulates words with ! until it hits a word that doesn't contain a !. At this point, it joins the words in bang_wl and appends to the output_wl list.

Upvotes: 3

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 250881

Use itertools.groupby:

>>> from itertools import groupby
>>> out = []
>>> for lst in words:
    d = []
    for k, g in groupby(lst, lambda x: '!' in x):
        if k:
            d.append(', '.join(g))
        else:
            d.extend(g)
    out.append(d)
...     
>>> out
[['this', 'that!', 'riff', 'raff'],
 ['hip', 'hop!, flip!', 'flop'],
 ['humpty', 'dumpty!, professor!, grumpy!']]

Upvotes: 6

Related Questions