1

I am trying to merge two list (within a list of list) if a certain conditions are met.

An example:

li = [[18, 19, 20, 21, 22], [25, 26, 27], [59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69]]

li2 = [[15, 16, 17], [32, 33, 34, 35], [89, 90, 91], [95, 96, 97, 98]]

The condition is that if the difference (or the distance rather) between each lists is less than 7 units, the list will be merged. After the list is merged, I would like to fill in the missing numbers.

Hence the expected outcome is as below:

li = [[18, 19, 20, 21, 22, 23, 24, 25, 26, 27], [59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69]]

li2 = [[15, 16, 17], [32, 33, 34, 35], [89, 90, 91, 92, 93, 94, 95, 96, 97, 98]]

This is the current code that I am working on:

new_li = []
for i in np.arange(len(li) - 1):
    current_item, next_item = li[i], li[i+1]

    if next_item[0] - current_item[-1] <= 7:
        new_li.append(current_item + next_item)

    else:
        new_li.append(next_item)

Which gives me:

new_li = [[18, 19, 20, 21, 22, 25, 26, 27], [59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69]] 

And applying the code for the li2:

new_li2 = [[32, 33, 34, 35], [89, 90, 91], [89, 90, 91, 92, 93, 95, 96, 97, 98]]

Before I can even begin to fill in the missing values, my code is incorrect and can't seem to get the last part of the code correct. Any help or tips to improve my codes is greatly appreciated!

MSeifert
  • 145,886
  • 38
  • 333
  • 352
Karl Chan
  • 11
  • 2

3 Answers3

0

You need to skip the next list if its already added. Also if the current set doesn't meets condition with next set you need to add current set to result list not the next set.

Following code is corrected :

li = [[18, 19, 20, 21, 22], [25, 26, 27], [59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69]]
li2 = [[15, 16, 17], [32, 33, 34, 35], [89, 90, 91], [95, 96, 97, 98]]

new_li = []
for i in range(len(li2) - 1):
    current_item, next_item = li2[i], li2[i+1]

    if next_item[0] - current_item[-1] <= 7:
        new_li.append(current_item + next_item)
        i+=1
    else:
        new_li.append(current_item)


for item in new_li:
    print (item)
sourabh1024
  • 647
  • 5
  • 15
0

I prefer generator functions (see for example "What does the “yield” keyword do?") for this sort of task because you can easily use them in loops (without having to create a complete list) and convert them to a list if necessary (or other containers).

Basically this would meet your requirements:

def merge(li):
    current = None
    for sublist in li:
        if current is None:
            # First iteration, just set the "current" then process the next sublist.
            current = sublist
            continue
        if sublist[0] - current[-1] <= 7:
            # first append the missing values
            current.extend(range(current[-1] + 1, sublist[0]))
            # then append the next sublist
            current.extend(sublist)
        else:
            # Difference is greater than 7 yield the current list and then reset it.
            yield current
            current = sublist
    # Exhausted, yield the last current then exit.
    yield current

This gives the expected result for your cases (note that it requires a list() around the generator function call):

>>> list(merge([[18, 19, 20, 21, 22], [25, 26, 27], [59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69]]))
[[18, 19, 20, 21, 22, 23, 24, 25, 26, 27], [59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69]]

>>> list(merge([[15, 16, 17], [32, 33, 34, 35], [89, 90, 91], [95, 96, 97, 98]]))
[[15, 16, 17], [32, 33, 34, 35], [89, 90, 91, 92, 93, 94, 95, 96, 97, 98]]

It could also merge several sublists, which would be a problem in your case:

>>> list(merge([[1,2], [5, 6], [10,11], [200]))
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [200]]
MSeifert
  • 145,886
  • 38
  • 333
  • 352
0

You can proceed as follows:

def merge(li):
  return [li[i] + range(max(li[i]) + 1, min(li[i+1])) + li[i+1] 
          if min(li[i+1]) - max(li[i])<7 
          else li[i] for i in range(len(li)-1)]

Since the lists are sorted, you can replace max(list_name) with list_name[-1] and min(list_name) with list_name[0]. Thus you can rewrite the solution as follows:

 def merge(li):
     return [li[i] + range(li[i][-1]+1, li[i+1][0]) + li[i+1] 
              if li[i+1][0] - li[i][-1] <7 
              else li[i] for i in range(len(li)-1)]

Execution details:

In [94]: def merge(li):
    ...:     return [li[i]+range(max(li[i])+1, min(li[i+1]))+li[i+1] 
             if min(li[i+1])-max(li[i])<7 
             else li[i] for i in range(len(li)-1)]
    ...: 
    ...: 

In [95]: merge(li)
Out[95]: [[18, 19, 20, 21, 22, 23, 24, 25, 26, 27], [25, 26, 27]]

In [96]: merge(li2)
Out[96]: [[15, 16, 17], [32, 33, 34, 35], [89, 90, 91, 92, 93, 94, 95, 96, 97, 98]]
Mohamed Ali JAMAOUI
  • 14,275
  • 14
  • 73
  • 117