递归比较两个列表

Posted

技术标签:

【中文标题】递归比较两个列表【英文标题】:comparing two lists recrusively 【发布时间】:2022-01-08 06:53:55 【问题描述】:

我的教授给了我一个 python 任务来比较 2 个二维列表,如果列表中的所有对象都相似,则返回 True,否则返回 False。 列表的类型为 list[list[int]]。 这必须使用递归来完成。 我不允许使用循环或切片。 (但可以访问列表中的特定索引) 列表的内部划分可能不同,但只要列表中相似位置的所有元素相似,函数就会返回 True。 例如 - [[1], [2, 3, 4]] , [[1, 2], [3, 4]] - 函数将返回 true。 我希望细节清楚,谢谢!

我的问题是找到解决这个问题的方法:)

【问题讨论】:

实际上,这在 Python 中有点无意义,因为 Python 可以将嵌套列表与其== 运算符进行比较... - 你可以开玩笑地写def compare(lol1, lol2): return lol1 == lol2 - 这绝对是一个工作Python 中的解决方案 ;) . 这实际上是一个很棒的python作业!感谢分享。但是你有问题吗? @Gwang-JinKim 我理解问题陈述的方式,你的“解决方案”根本行不通。 哈哈遗憾的是,我们的大多数任务都是毫无意义的,只是为了让我们无缘无故地努力工作......我只能使用 == 来比较列表中的 int 而不是列表本身 :( 我的意思是开玩笑——这种任务通常来自口语。但是对于递归,您必须比较列表的第一个元素(lisp 中的car)和列表的其余部分(cdr)-但问题是-您不允许使用切片...以及如何使用可以在不切片的情况下获取列表的其余部分吗? ... 【参考方案1】:
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)

【讨论】:

【参考方案2】:

通常你对列表中的carcdrfirstrest)执行l[0]l[1:]

这项任务最大的挑战是禁止切片。

但是有

first, *rest = your_list 

有效!不仅不用切片,而且不用索引。

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.



 

这适用于 Python3,但不适用于 Python2。

对于 Python2 和 Python3,您可以使用函数定义:

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

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

单索引和.pop()

也许你老师的想法是:

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

但是这个解决方案是有问题的,因为它改变了 输入列表,因为 Python 执行 call-by-reference 而不是 call-by-value。为避免这种情况,必须首先对列表进行深度复制。可以通过切片对列表进行浅拷贝,但不允许切片...

喜欢:

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

【讨论】:

以上是关于递归比较两个列表的主要内容,如果未能解决你的问题,请参考以下文章

如何递归地分割列表并比较相邻的值

查找列表中的最小元素(递归) - Python

(链表)链表的一些合并问题

分治算法在子列表中找到两个匹配的元素

合并两个有序列表——递归&非递归

scala中的特别函数递归地连接两个列表:不使用“concat”