python - 循环遍历并行列表删除匹配项,直到不再存在匹配项

标签 python list python-3.x duplicates

我有 3 个并行列表,代表一个 3 元组(日期、描述、金额),还有 3 个新列表,我需要合并这些列表而不创建重复的条目。是的,列表有重叠的条目,但是这些重复的条目不会组合在一起(而不是所有重复项都是 0 到 x,所有新条目都是 x 到末尾)。

我遇到的问题是迭代正确的次数以确保捕获所有重复项。相反,我的代码会继续运行,并保留重复的代码。

for x in dates:
    MoveNext = 'false'
    while MoveNext == 'false':
        Reiterate = 'false'
        for a, b in enumerate(descriptions):
            if Reiterate == 'true':
                break
            if b in edescriptions:
                eindex = [c for c, d in enumerate(edescriptions) if d == b]
                for e, f in enumerate(eindex):
                    if Reiterate == 'true':
                        break
                    if edates[f] == dates[a]:
                        if eamounts[f] == amounts[a]:
                            del dates[a]
                            del edates[f]
                            del descriptions[a]
                            del edescriptions[f]
                            del amounts[a]
                            del eamounts[f]
                            Reiterate = 'true'
                            break
                        else:
                            MoveNext = 'true'
                    else:
                        MoveNext = 'true'
            else:
                MoveNext = 'true'

我不知道这是否是巧合,但我目前正好删除了一半的新项目,而另一半仍然保留。事实上,应该远远少于剩下的。这让我认为 for x in days: 没有迭代正确的次数。

最佳答案

我建议采用不同的方法:不要尝试从列表(或更糟糕的是,几个并行列表)中删除项目,而是运行输入并仅生成通过测试的数据 ---在本例中,是您以前从未见过的数据。使用单个输入流就容易得多。

您的数据列表迫切需要制成对象,因为如果没有其他两个数据,每一个数据(例如日期)都毫无意义......至少对于您当前的目的而言。下面,我首先将每个三元组组合到一个 Record 实例中,即 collections.namedtuple 。它们非常适合这种一次性使用的工作。

在下面的程序中,build_records 从三个输入列表创建 Record 对象。 dedup_records 合并多个 Record 对象流,使用 unique 过滤掉重复项。保持每个函数较小(大部分 main 函数是测试数据)使得每个步骤都易于测试。

#!/usr/bin/env python3

import collections
import itertools


Record = collections.namedtuple('Record', ['date', 'description', 'amount'])


def unique(records):
    '''
    Yields only the unique Records in the given iterable of Records.
    '''
    seen = set()
    for record in records:
        if record not in seen:
            seen.add(record)
            yield record
    return


def dedup_records(*record_iterables):
    '''
    Yields unique Records from multiple iterables of Records, preserving the
    order of first appearance.
    '''
    all_records = itertools.chain(*record_iterables)
    yield from unique(all_records)
    return


def build_records(dates, descriptions, amounts):
    '''
    Yields Record objects built from each date-description-amount triplet.
    '''
    for args in zip(dates, descriptions, amounts):
        yield Record(*args)
    return


def main():
    # Sample data
    dates_old = [
      '2000-01-01',
      '2001-01-01',
      '2002-01-01',
      '2003-01-01',
      '2000-01-01',
      '2001-01-01',
      '2002-01-01',
      '2003-01-01',
      ]
    dates_new = [
      '2000-01-01',
      '2001-01-01',
      '2002-01-01',
      '2003-01-01',
      '2003-01-01',
      '2002-01-01',
      '2001-01-01',
      '2000-01-01',
      ]
    descriptions_old = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']
    descriptions_new = ['b', 'b', 'c', 'a', 'a', 'c', 'd', 'd']
    amounts_old = [0, 1, 0, 1, 0, 1, 0, 1]
    amounts_new = [0, 0, 0, 0, 1, 1, 1, 1]
    old = [dates_old, descriptions_old, amounts_old]
    new = [dates_new, descriptions_new, amounts_new]

    for record in dedup_records(build_records(*old), build_records(*new)):
        print(record)
    return


if '__main__' == __name__:
    main()

这将 16 个输入记录减少到 11 个:

Record(date='2000-01-01', description='a', amount=0)
Record(date='2001-01-01', description='b', amount=1)
Record(date='2002-01-01', description='c', amount=0)
Record(date='2003-01-01', description='d', amount=1)
Record(date='2000-01-01', description='b', amount=0)
Record(date='2001-01-01', description='b', amount=0)
Record(date='2003-01-01', description='a', amount=0)
Record(date='2003-01-01', description='a', amount=1)
Record(date='2002-01-01', description='c', amount=1)
Record(date='2001-01-01', description='d', amount=1)
Record(date='2000-01-01', description='d', amount=1)

请注意,yield from ... 语法需要 Python 3.3 或更高版本。

关于python - 循环遍历并行列表删除匹配项,直到不再存在匹配项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39049905/

相关文章:

python - 重组程序以使用 asyncio

Python:用元组值更新字典键

python - 加快动画 gif kivy 的加载

python - 在 Python 中使用生成器/"with ... as"的紧凑方式

python - 在 python 列表中搜索空列表不准确吗?

c# - 庞大的长列表和搜索最近的元素

python - 为什么 python 中的元素树在 XML 中添加额外的新行和空格

python 3D numpy 数组时间索引

python - 为什么修改类属性不会修改 Python 中的对象属性?

c# - 将 C# 列表列表导出到 Excel