如何从列表中删除重复项,同时还向相应的列表项添加重复项计数?

时间:2018-07-03 05:02:22

标签: python list

我的问题与

相同

除了我也希望重复项反映项目字符串本身中的重复项(在括号中)。

示例输入:

myList = ["paper", "Plastic", "aluminum", "PAPer", "TIN", " paper", "glass", "tin", "PAPER", "Polypropylene Plastic"]

唯一可接受的输出:

myList = ["paper (3)", "Plastic", "aluminum", "TIN (2)", " paper", "glass", "Polypropylene Plastic"]

注意:

  • 请注意,如果某个项目("Polypropylene Plastic")恰好包含另一个项目("Plastic"),我仍然希望保留这两个项目。

  • 因此,大小写可能会有所不同,但是该项目必须是字符对字符的匹配,才能被删除。

  • 原始列表顺序必须保留。

  • 该项目的第一个实例之后的所有重复项均应删除。该第一个实例的原始案例以及所有非重复项的原始案例都应保留。

我正在寻找最快的方法,以在Python 2.7中完成此操作。

3 个答案:

答案 0 :(得分:2)

在最初的问题中,您大概(我只是看了一下)使用了set的大小写折叠的字符串来查看您是否有一个新字符串或一个重复字符串,并在进行过程中建立一个新列表

您可以将其替换为Counter而不是set。但是然后您需要构建列表,然后返回并使用计数对其进行编辑。

因此,用set替换两者 Counter / OrderedDict和输出列表,其中d = collections.OrderedDict() for item in myList: caseless = item.lower() try: d[caseless][1] += 1 except KeyError: d[caseless] = [item, 1] 存储每个折叠案例的项目计数对:

myList = []
for item, count in d.values():
    if count > 1:
        item = '{} ({})'.format(item, count)
    myList.append(item)

…,然后对该字典进行传递以生成输出列表:

myList = ['{} ({})'.format(item, count) if count > 1 else item for item, count in d.values()

您可以使它更简洁(例如%),这也将使它以较小的恒定因子更快。

您也可以使用format而不是%d来节省几纳秒的时间,甚至可以使用%s而不是a[0] += 1来节省几纳秒的时间(尽管我认为最后部分直到2.7都不再适用。

取决于您的平台,a[1] += 1可能比a[0]更快或更慢。因此,请尝试两种方式,如果[count, item]更快,请使用[item, count]对而不是__slots__。如果您有很多傻瓜,则可能要考虑使用in的类,它实际上比列表要快一些,但创建起来要慢得多。

此外,使用d.__contains__测试,或者将try本地存储,可能比draggable: false更快,也可能更慢,具体取决于您希望重复多少次有,因此请在您的实际数据而不是玩具数据集上尝试这三种方式。

答案 1 :(得分:1)

您也可以尝试使用collections.Counter()对象来跟踪计数,并使用无大小写的单词作为参考来跟踪所看到的单词。然后,当您完成对输入列表的迭代时,请更新结果列表,以使单词计数的形式为 1 2 3 0.4 0.41 0.39 (如果计数大于1)。

代码:

Requirement already satisfied: gevent in c:\program files (x86)\python36-32\lib\site-packages (1.3.4)
Requirement already satisfied: cffi>=1.11.5; sys_platform == "win32" and platform_python_implementation == "CPython" in c:\program files (x86)\python36-32\lib\site-packages (from gevent) (1.11.5)
Requirement already satisfied: greenlet>=0.4.13; platform_python_implementation == "CPython" in c:\program files (x86)\python36-32\lib\site-packages (from gevent) (0.4.13)
Requirement already satisfied: pycparser in c:\program files (x86)\python36-32\lib\site-packages (from cffi>=1.11.5; sys_platform == "win32" and platform_python_implementation == "CPython"->gevent) (2.18)
tweepy 3.6.0 has requirement requests>=2.11.1, but you'll have requests 2.10.0 which is incompatible.

输出:

%s (%d)

答案 2 :(得分:1)

这里是一个使用单个Counter的版本,通过在传递它们时从set中弹出密钥,从而避免了@RoadRunner解决方案中使用另一个Counter的情况。如果有很多重复项,这可能比OrderedDict解决方案要慢一些,但是会使用更少的内存:

from collections import Counter

words = ["paper", "Plastic", "aluminum", "PAPer", "TIN", " paper", "glass", "tin", "PAPER", "Polypropylene Plastic"]

counter = Counter(w.lower() for w in words)

result = []
for word in words:
    key = word.lower()
    if key in counter:
        count = counter[key]
        if count == 1:
            result.append(word)
        else:
            result.append('{} ({})'.format(word, count))
        counter.pop(key)

注意对于Python> = 3.3的用户,应使用casefold而不是lower