Haytham
Haytham

Reputation: 502

How to evaluate two items of the same list and return their sum if equal?

This is part of an online course homework where we are asked to build a merge function for the 2048 game. The function takes a list as an argument and iterate through it to return another list where the same elements are merged, and the list is updated.

So far I'm able to check for empty tiles "zeros" and return a list that has the rest of the numbers. Code:

def merge(line):
"""
A function that merges a single row or column in 2048.
"""
output =  [0]* len(line)
output1 = [0]* len(line)
for num in line:
    if num != 0:
        output.insert(-1,num)
        del output[0]

the next step where I am stuck is how to evaluate the new list to merge "sum" items that are of the same value.

I want to extend the function to something that does this:

for num in output:
     if num == "the next item in list":
     return the sum of both items and skip to the next item

     output1.insert(-1, "the sum of the two items")
     del output1[0]

we were provided with tests to run to see if our code is functioning properly

[2, 0, 2, 4] should return [4, 4, 0, 0],
[0, 0, 2, 2] should return [4, 0, 0, 0],
[2, 2, 0, 0] should return [4, 0, 0, 0],
[2, 2, 2, 2, 2] should return [4, 4, 2, 0, 0],
[8, 16, 16, 8] should return [8, 32, 8, 0]

your help is much appreciated

Upvotes: 2

Views: 261

Answers (3)

Godrebh
Godrebh

Reputation: 564

This is how I attempted it: I remove all 0s, but I remember, how many there were. Then I go through the list, comparing always two items. If they are the same, then I save the sum and remember, that I do not want to regard the second one in the next step. If they are not the same, then I just add the value as it is. Finally, I look at the last value and add the missing 0s.

l = [8,16,16,8]

z = l.count(0)
l = [x for x in l if x!=0]
new = []
go_over = []
for i in range(len(l)-1):
    if i in go_over:
        continue
    if l[i] == l[i+1]:
        new.append(2*l[i])
        go_over.append(i+1)
    else:
        new.append(l[i])

if len(l)-1 not in go_over:
    new.append(l[-1])   
new += [0]*(len(go_over)+z)

print(new)

Upvotes: 0

Copperfield
Copperfield

Reputation: 8510

I also did it with groupby and also the grouper recipe

from itertools import groupby, izip_longest, ifilter, repeat

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

def merge(line):
    size = len(line)
    resul = []
    for num,val in groupby(ifilter(bool,line)):
        for pair in grouper(val,2,0):
            resul.append( sum(pair) )
    if len(resul) < size:
        resul.extend( repeat(0,size-len(resul)) )
    return resul

first with ifilter I eliminate the 0, then gruopby give me the numbers in, well, groups of the same number, and with grouper I build pair with those that I sum and append to the result. Finally I append the missing 0 to the end with the extend method if needed

Upvotes: 0

Brendan Abel
Brendan Abel

Reputation: 37529

I did it in two steps, too. Move all the numbers left, removing any zeros. Then iterate through the list of numbers combining 2 like numbers. I used itertools.groupby to make the iterating through like numbers easier.

groupby returns an iterator for each group of like numbers so:

[2,2,0,0]

becomes

[(2, [2, 2]), (0, [0, 0])]

It makes it easier to process each similar group as a separate chunk.

For groups of similar numbers like [2,2] or [2,2,2], the output will always be a list of half the length and the items in the list will all be 2*n (for odd length lists, there is an extra last element that will just be n).

from itertools import groupby

def merge(line):
    cnt = len(line)
    # Move all numbers left, removing zeros
    line = [num for num in line if num != 0]
    out = []
    # Combine like numbers
    for num, niter in groupby(line):
        ncnt = len(list(niter))
        out.extend([num * 2] * (ncnt // 2))
        if ncnt % 2:
            out.append(num)
    # Right pad the list with zeros to the original line length
    out.extend([0] * (cnt - len(out)))
    return out

Upvotes: 1

Related Questions