【问题标题】:nth repeated element in a list列表中的第 n 个重复元素
【发布时间】:2018-04-22 04:55:13
【问题描述】:

我对以下解决方案的更多 Pythonic 和高性能方法感兴趣。

def nthFrequent(arr,n):

    d = dict((x, arr.count(x)) for x in set(arr))

    value = sorted(d.values(), reverse=True)
    # Pick nth repeated element
    nthrepeat = value[n-1]

    for (key, val) in d.iteritems():
        if val == nthrepeat:
            return key


a=[1,2,3,4,5,6,7,92,3,2,35,9,2,43,4,9,9,9]

print nthFrequent(a,2)

上面的代码将返回 2,因为 2 在 9 之后重复了 3 次,即 4 次。

我正在寻找更优雅的 lambda 使用方式,但我尝试了以下方法,但没有得到所需的结果。

max(((item, a.count(item)) for item in set(a)), key=lambda k: k[1])[0]

上面的将获得最大重复值,即。 9.

如何获得第二个或第 n 个?

【问题讨论】:

  • 你能提供一个示例输入和预期输出吗?
  • 不确定你想在这里用 lambda 做什么,但如果你只是想找到一个恰好重复 N 次的元素,最好使用 Counter 或手动计算出现次数(不调用 @ 987654324@)。您当前的解决方案是 O(N^2),但您可以在 O(N) 内解决此问题。

标签: python list repeat


【解决方案1】:

对于 collections.Counter,这非常简单。但是请注意,如果 n 值更改为 3,此解决方案将仅返回 3 或 4 之一,因为在这种情况下会出现平局。

import collections

def nthFrequent(arr,n):
    return sorted([(v, k) for k, v in collections.Counter(arr).items()], reverse=True)[n-1][1]

a = [1,2,3,4,5,6,7,92,3,2,35,9,2,43,4,9,9,9]

print nthFrequent(a,2)

另外值得注意的是:元组列表按元组的 0 索引元素排序。因此,您可以使用带有 (count, value) 的元组并返回该值。排序中不需要 lambda。

如果您真的想在没有导入的情况下执行此操作,那么即使这样实现也会更快:

def nthFrequent3(arr, n):
    d = {}
    for v in arr:
        if v not in d:
            d[v] = 0
        d[v] += 1

    return sorted([(v, k) for k, v in d.items()], reverse=True)[n-1][1]

如果您将来决定使用导入,那么也可以看看 itertools。它也有一些方便的工具

def nthFrequent2(arr, n):
    for i, (value, _) in enumerate(itertools.groupby(sorted(arr))):
        if i == n - 1:
            return value

【讨论】:

  • 谢谢@sberry。我的意图是尽量避免收藏。
  • @paddu 这里有什么具体原因吗?您要求更多“pythonic 和性能”的东西,这两者兼而有之。
  • 嗯,它当然是高性能的和 Pythonic 的。但是,我正在寻找一些没有使用任何模块导入的东西。感谢您承受痛苦并向我解释这一点。
  • @paddu 我很想知道您为什么要在不使用导入的情况下执行此操作?我的意思是,它们是标准库的一部分是有原因的。
  • @paddu,如果你担心污染命名空间,你可以只导入你需要的一个函数:from collections import Counter
【解决方案2】:

如果您正在寻找单线,以下应该可以工作:

return sorted(((item, a.count(item)) for item in set(a)), key=lambda k: k[1], reverse=True)[n-1][0]

虽然上面使用了更多 Python 语言功能,但我实际上更喜欢原始代码的可读性。

附带说明,在您的原始代码中,您应该return key,因为您当前正在尝试打印一个不返回值的函数。

如果您关心关系,正如@sberry 提到的,您可以这样做:

count 相同时取最小值:

return sorted(((item, a.count(item)) for item in set(a)), 
    key=lambda k: (k[1], k[0]), reverse=True)[n-1][0]

count 相同时取最大值:

return sorted(((item, a.count(item)) for item in set(a)), 
    key=lambda k: (k[1], -k[0]), reverse=True)[n-1][0]

【讨论】:

  • 谢谢,return 是我在 lambda 和原始代码之间尝试时搞砸的。
【解决方案3】:

Narr的长度,这一行:

d = dict((x, arr.count(x)) for x in set(arr))

按照 N2 的顺序执行多个步骤。首先,遍历arr 以找到它的唯一元素(最坏的情况是每个元素都是唯一的)。其次,对于每个唯一元素,再次遍历整个列表以计算该元素出现的次数。您的单线解决方案也是 N2 的顺序。

这是很多不必要的重复步骤。您只需要查看arr 的每个元素一次。一步,您可以:

  • 检查你是否已经看过这个元素

  • 增加该元素的计数器

像这样:

counter = {}

for x in arr:
    if x not in counter:
        counter[x] = 0
    counter[x] += 1

pairs = sorted(counter.iteritems(), key=lambda pair: pair[1], reverse=True)

key, count = pairs[n]
return key

在最坏的情况下,每个元素都是唯一的,由于排序,此代码会按照 N*log(N) 的顺序执行多个步骤。 (通过arr 的顺序是N,因为Python 中的dict 查找的顺序是摊销 1。)

【讨论】:

  • counter[x] = counter.get(x, 0) + 1 避免需要 if 条件。
猜你喜欢
  • 2018-05-27
  • 2018-02-07
  • 1970-01-01
  • 2018-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-10
相关资源
最近更新 更多