Help a fruit packer sort out the bad apples. 

There are 7 varieties of apples, all packaged as pairs and stacked in a fruit box. Some of the apples are spoiled. The fruit packer will have to make sure the spoiled apples are either removed from the fruit box or replaced. Below is the breakdown:

Apple varieties are represented with numbers, `1 to 7`

A fruit package is represented with a 2 element array `[4,3]`

A fruit package with one bad apple, or a bad package, is represented with `[2,0]` or `[0,2]`

A fruit package with two bad apples, or a rotten package, is represented with `[0,0]`

A fruit box is represented with:

```
[ [ 1, 3 ],
  [ 7, 6 ],
  [ 7, 2 ],
  [ 1, 3 ],
  [ 0, 2 ],
  [ 4, 5 ],
  [ 0, 3 ],
  [ 7, 6 ] ]

```

Write a program to clear the fruit box off bad apples. 

The INPUT will be a fruit box represented with a 2D array: `[[1,3],[7,6],[7,2],[1,3],[0,2],[4,5],[0,3],[7,6]]`

The OUTPUT should be the fruit box void of bad apples: `[[1,3],[7,6],[7,2],[1,3],[2,3],[4,5],[7,6]]`

Conditions to be met:

1.A bad package should have the bad apple replaced if there is another bad package with a good apple to spare. Else, the bad package should be discarded.

2.The order of the packages in the fruit box should be preserved. Repackaging happens from the top of the fruit box `index = 0` to the bottom `nth index`. Also note how fruits in a package are ordered when repacking. Example shown in INPUT/OUPUT above.

3.Rotten packages should be discarded. 

4.There can be packages with the same variety of apples, e.g `[1,1]`, this is not a problem.

Difficulty: introductory

Starter code:

def bad_apples(apples):
	

Solutions:
def bad_apples(apples):
    lst, notFull = [], []
    for a,b in apples:
        if (bool(a) ^ bool(b)) and notFull:  lst[notFull.pop()].append(a or b)                  # One bad and partially full box already present: fill it (as second element)
        elif a and b:                        lst.append([a,b])                                  # 2 good ones: keep as they are
        elif a or b:                         notFull.append(len(lst)) ; lst.append([a or b])    # 1 good but no partial box: archive
    if notFull: lst.pop(notFull.pop())                                                          # If 1 not full box remains: remove it
    return lst

def bad_apples(apples):
    packed = []
    while apples:
        package = apples.pop(0)
        if min(package) > 0:
            # Both apples are positive
            packed.append(package)
        elif max(package) == 0:
            # Both apples are rotten
            continue
        else: # Only one good apple
            # Filter for other packs with one good apple
            singles = filter(lambda x: min(x) == 0 and max(x) > 0, apples)
            try:
                # Try to get the next filtered package
                next_single = next(singles)
                # If found, remove from remaining apples and repackage
                apples.remove(next_single)
                packed.append([max(package), max(next_single)])
            except StopIteration:
                # If not found, discard and do nothing
                pass
    return packed

def bad_apples(apples):
    bad = (x if x else y for x,y in apples if (not x) ^ (not y))
    result, flag = [], True
    for x in apples:
        if all(x): result.append(x)
        elif any(x):
            if flag:
                try: result.append([next(bad), next(bad)])
                except StopIteration: pass
            flag = not flag
    return result

def bad_apples(apples):
    free = None
    i = 0
    while i<len(apples):
        if 0 in apples[i]:
            if set(apples[i])=={0}:
                apples.pop(i)
            else:
                apples[i].remove(0)      
                if free!=None:
                    apples[free].append(apples[i][0])
                    apples.pop(i)
                    free = None
                else:
                    free = i
            i-=1        
        i+=1
    if free!=None: apples.pop(free)
    return apples
        


def bad_apples(a):
    li, visited = [], []
    for i, j in enumerate(a):
        if i not in visited and sum(j) != 0:
            if 0 in j:
                find = next((k for k in range(i+1,len(a))if 0 in a[k]and sum(a[k])!=0), 0)
                if find:
                    make = [j[0]or j[1],a[find][0]or a[find][1]]
                    visited.append(find) ; li.append(make)
            else : li.append(j)
    return li

def bad_apples(apples):
    apples = [list(filter(None, xs)) for xs in apples]
    apples = list(filter(None, apples))
    idxs = [i for i, x in enumerate(apples) if len(x) == 1]
    if len(idxs) % 2 == 1:
        del apples[idxs.pop()]
    for i in reversed(range(0, len(idxs), 2)):
        apples[idxs[i]].append(apples.pop(idxs[i+1]).pop())
    return apples

def bad_apples(apples):
    good_packages, bad_packages = [], []
    for i, box in enumerate(apples):
        if box[0] and box[1]:
            good_packages.append([i, box])
        elif box[0] or box[1]:
            bad_packages.append([i, box[1] if box[1] else box[0]])

    for a, b in zip(*[iter(bad_packages)]*2):
        good_packages.append([a[0], [a[1], b[1]]])
    return [box for _, box in sorted(good_packages)]

def bad_apples(a):
    b = list(map(lambda x: [i for i in x if i != 0], a))
    for x,y in enumerate(b):
        for i,j in enumerate(b):
            if len(y)==1 and len(j)==1 and x != i:
                b[x] = y+j
                b.remove(j)
                break
    return [x for x in b if len(x)==2]

from itertools import chain, repeat
mul = lambda x: x[0]*x[1]
def bad_apples(apples):
    inserting = [sum(pair) for pair in apples if mul(pair) == 0 and sum(pair)> 0]
    ins_pairs = chain(chain(*zip(list(zip(*[iter(inserting)] * 2)), repeat(None))),repeat(None))
    return list(filter(bool, [pair if mul(pair)>0  else list(next(ins_pairs) or ()) for pair in apples if sum(pair)>0]))

def bad_apples(apples):
    a = apples[:]
    for i in range(len(a)-1):
        if a[i].count(0) == 1:
            for j in range(i+1, len(a)):
                if a[j].count(0) == 1:
                    a[i] = [sum(a[i]), sum(a[j])]
                    a[j] = [0,0]
                    break
    return [i for i in a if 0 not in i]