Molly Zhou
Molly Zhou

Reputation: 357

How to fill the none values to a list of tuples using Python

I want to write a code that can merge list a&b to get list c by filling list a with tuples, of which tuple[0] is none and tuple[1] is the values that are in b but not in a[index][1]. For instance,

a=[(1,None),(2,4),(3,6),(4,None),(5,9)];
b=[4,5,6,7,9]

The desired c should be

c=[(1,None),(2,4),(None,5),(3,6),(4,None),(None,7),(5,9)]

I wrote a simple code as below that appended (None,5) at the end of the list. My actual intention is to insert it as the order of list b (I'm not sure how). Also, it seems to be inefficient as the number of elements in each list grows.

import itertools
a=[(1,None),(2,4),(3,6),(4,None),(5,9)]
b=[4,5,6,7,9]
for elem2 in b:
    for elem1 in a:
        if elem1[1]==elem2:
            #print(str(elem2) +'is in.')
            break
    else:
        a.append((None,elem2))
print(a)

Is there a special function that can achieve the merge?

Upvotes: 4

Views: 1981

Answers (2)

6502
6502

Reputation: 114559

If you want to keep the elements ordered by second value then you need to implement a merge operation. The general idea is "keep picking the lower element and add that". If the elements are sorted also there is no need to use a set for knowing if an element is present or not:

c = []
ia = ib = 0
while ia < len(a) and ib < len(b):
    if a[ia][1] == b[ib]:
        # same second element, a wins
        c.append(a[ia])
        ia += 1
        ib += 1
    elif a[ia][1] is None or a[ia][1] < b[ib]:
        # a element is smaller and comes first
        c.append(a[ia])
        ia += 1
    else:
        # b element is smaller and comes first
        v.append((None, b[ib]))
        ib += 1
# at the end may be there are extra a elements, add all of them at once
if ia < len(a):
    c += a[ia:]
# or there may be extra b elements
while ib < len(b):
    c.append((None, b[ib:]))
    ib += 1

Upvotes: 1

CryptoFool
CryptoFool

Reputation: 23119

Here's a solution that works. It could likely be done more elegantly, but I'm pretty sure it works for any input values, making only a single pass:

a = [(1, None), (2, 4), (3, 6)]
b = [4, 5, 6]
i = 1
while True:
    if i == len(a):
        for v in b:
            a.append((None, v))
        break
    while len(b) and a[i][1] >= b[0]:
        v = b.pop(0)
        if a[i][1] > v:
            a.insert(i, (None, v))
            i += 1
    i += 1
print(a)

Result:

[(1, None), (2, 4), (None, 5), (3, 6)]

Tried it with more input too:

b = [4, 5, 6, 7, 8, 9, 10]

which gives you:

[(1, None), (2, 4), (None, 5), (None, 6), (None, 7), (3, 8), (None, 9), (None, 10)]

Upvotes: 0

Related Questions