【问题标题】:Python / Collections - Remove elements that appear same number of timesPython / Collections - 删除出现相同次数的元素
【发布时间】:2016-05-11 10:45:48
【问题描述】:

示例 1:

import collections

list = ['Mike', 'Mike', 'Mike', 'Jhon', 'Jhon', 'Rob', 'Rob', 'Carl', 'Carl']
list_counter = collections.Counter(list)
>> Counter({'Mike': 3, 'Rob': 2, 'Jhon': 2, 'Carl': 2})

示例 2:

import collections
list = ['Sam', 'Sam', 'Sam', 'Sam', 'Mike', 'Mike', 'Mike', 'Jhon', 'Jhon', 'Rob', 'Rob']
list_counter = collections.Counter(list)
>> Counter({'Sam': 4, 'Mike': 3, 'Rob': 2, 'Jhon': 2})

我要做的就是验证列表中是否出现 2 个或更多元素相同的次数,然后删除它们。

在示例 1 中,Rob、Jhon 和 Carl 将被删除,它们是在列表中出现 2 次的 3 个元素。在示例 2 中,Rob 和 Jhon 将被删除,而 Sam 和 Mike 则可以并留在列表中。如果列表中仅出现 1 个元素(例如 Jhon n 次),则不会删除任何内容。

【问题讨论】:

  • 你有没有尝试过?
  • 其实我不知道,我只知道我可以用 list_counter["Sam"] 轻松检索每个元素的出现
  • 您是在删除计数为 2 的元素,不多不少?
  • Counter({'Mike': 3, 'Rob': 2, 'Jhon': 2, 'Carl': 2,"foo":4,"bar":4}) 会发生什么?
  • @PadraicCunningham ...如果我已经很好地理解了OP在这里的意图,那么应该是Counter({'Mike':3}) ... nop?

标签: python collections


【解决方案1】:

如果要删除所有出现频率相同的名称至少两次:

import collections

lst = ['Mike', 'Mike', 'Mike', 'Jhon', 'Jhon', 'Rob', 'Rob', 'Carl', 'Carl',
       "foo","foo","foo","foo","bar", "bar", "bar", "bar"]
list_counter = collections.Counter(lst)

# count the frequency 
times = collections.Counter(list_counter.values())

# keep names that do not appear at the same frequency as any other names
lst[:] = [name for name,v  in list_counter.items() if times[v] < 2]
print(lst)

这会给你留下:

['Mike']

如果您还想确保计数不是 1:

[name for name, v  in list_counter.items() if v == 1 or times[v] < 2]

如果您想保留所有 Mike,请遍历列表:

import collections

lst = ['Mike', 'Mike', 'Mike', 'Jhon', 'Jhon', 'Rob', 'Rob', 'Carl', 'Carl',
       "foo","foo","foo","foo","bar", "bar", "bar", "bar"]
list_counter = collections.Counter(lst)
times = collections.Counter(list_counter.values())

lst[:] = [name for name in lst if times[list_counter[name]] < 2]
print(lst)

这会给你:

 ['Mike', 'Mike', 'Mike']

【讨论】:

    【解决方案2】:

    您可以使用.values() 查找所有不同的金额,然后对出现&gt;= 2 次的值进行列表理解:

    values = collections.Counter(list_counter.values())
    result = [item for item in list if values[item] >= 2]
    

    不过,我不会使用 list 作为变量名,因为它会隐藏内置类型。

    【讨论】:

      【解决方案3】:

      我的方法是首先将具有相同count 的所有元素分组到defaultdict 对象中,然后根据过滤条件构建结果字典:

      >>> from collections import Counter, defaultdict  
      >>>
      >>> lst = ['Mike', 'Mike', 'Mike', 'Jhon', 'Jhon', 'Rob', 'Rob', 'Carl', 'Carl']
      >>> c = Counter(lst)
      >>> c
      Counter({'Mike': 3, 'Carl': 2, 'Rob': 2, 'Jhon': 2})
      >>>
      >>> d = defaultdict(list)
      >>> 
      >>> for k,v in c.items():
              d[v].append(k)
      >>> 
      >>> d
      defaultdict(<class 'list'>, {2: ['Jhon', 'Rob', 'Carl'], 3: ['Mike']})
      >>>
      >>> result = dict((*v,k) for k,v in d.items() if len(v) < 2)
      >>> result
      {'Mike': 3}
      >>> 
      

      【讨论】:

      • 这其实是O(n^2),使用Counters来计数是O(n)
      • 先建立计数,然后进行查找。
      • @PadraicCunningham...感谢您的提醒:)
      【解决方案4】:

      如果我猜对了,您希望将这些名称保留 2 次以上。 在这种情况下:

      [x for x,y in list_counter.iteritems() if y>2]
      

      【讨论】:

      • 不是“超过2次”;它与其他东西的次数相同。请注意,Mike 保留在两个示例中。
      【解决方案5】:
      import collections
      your_list = ['Sam', 'Sam', 'Sam', 'Sam', 'Mike', 'Mike', 'Mike', 'Jhon', 'Jhon', 'Rob', 'Rob']
      list_counter = collections.Counter(your_list)
      filtered_list = [item for item in your_list if list_counter.get(item) != 2]
      result = list(set(filtered_list))
      

      过滤后的列表是一种 Python 列表理解方式,用于比较您的列表项是否有 counter != 2。

      在例子二的情况下。

      ['迈克','迈克','迈克']

      现在做

      list(set(filtered_list))

      ['迈克']

      您不应将变量命名为“列表”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多