Home > OS >  comparing two lists recrusively
comparing two lists recrusively

Time:12-02

my professor gave me a python assignment to compare 2 two dimensional lists, return True if all objects in the lists are similar and False if they are not. the lists are of type- list[list[int]]. this must be done using recursion. I am not allowed to use loops or slicing. (but can access a specific index in the list) the inner division of the lists may be different but as long as all elements in similar places in the list are similar the function will return True. for example- [[1], [2, 3, 4]] , [[1, 2], [3, 4]] - the function will return true. I hope the details are clear, thank you!

my question is to find a solution to this problem :)

CodePudding user response:

Usually you do l[0] and l[1:] for car and cdr (first and rest) of the list.

The biggest challenge of this task is the forbidding of slicing.

But with

first, *rest = your_list 

It works! Not only without slicing but also without indexing.

def first(l):        # traditionally in Lisp languages `CAR`
    car, *cdr = l
    return car
    
def rest(l):         # traditionally in Lisp languages `CDR`
    car, *cdr = l
    return cdr

def comp(lol1, lol2):
    if len(lol1) == len(lol2) == 0:  # recursion end condition
        return True
    # if first elements are lists, `comp`are the firsts and the rests
    elif type(first(lol1)) == type(first(lol2)) == list:
        return comp(first(lol1), first(lol2)) and \
               comp(rest(lol1), rest(lol2))
    # if first elements are atoms (non-lists), `==` the firsts and `comp`are the rest
    else: # then the firsts are atoms!
        return first(lol1) == first(lol1) and \
               comp(rest(lol1), rest(lol2))
    
# traditionally in Lisp languages, you test not for list
# but for `atom` (whether the first elements of the lists are
# non-lists -> atomar). But `atom` is not that easy test in Python.
# so it is must more easy to ask whether both first elements are lists - and 
# if not - then it is clear that the first elements of non-empty lists must be non-lists => atoms.



 

This works with Python3 but not with Python2.

For Python2 and Python3, you can use the function definitions:

def first(l):
    return (lambda x, *y: x)(*l)

def rest(l):
    return (lambda x, *y: y)(*l)

With single indexing and .pop()

Perhaps what your teacher thought of was:

def first(l):
    return l[0]
    
def rest(l):
    if l != []:
        l.pop()
        return l
    else:
        return []

# For definition of the `comp()` function see above

But this solution is problematic, because it changes the input list, since Python does call-by-reference and not call-by-value. To avoid this, one has to deep-copy the list first. One can shallow-copy a list with slicing, but slicing is not allowed ...

Like:

q = [1, 2, [3, 4], [5, 6, 7], 8]
comp(q, q)
## True
# so far so good, but:
q
## []

CodePudding user response:

a1 = [[1], [2, 3, 4]]
a2 = [[1, 2], [3, 4]]

def get_next_indexes(i, j, a):  # function for getting next indexes based on previous
    return (i   1, 0)if j >= len(a[i]) - 1 else (i, j   1)

def compare_lists(i1, j1, i2, j2):  # i1 and j1 - indexes for first array; i2 and j2 - indexes for second array
    if i1 >= len(a1) or i2 >= len(a2):
        print("Two lists are equal.")
        exit(0)
    if a1[i1][j1] != a2[i2][j2]:
        print("Two lists are not equal.")
        exit(0)
    print(get_next_indexes(i1, j1, a1))
    compare_lists(*get_next_indexes(i1, j1, a1), *get_next_indexes(i2, j2, a2))

compare_lists(0, 0, 0, 0)
  • Related