【问题标题】:Best / most pythonic way to remove duplicate from the a list and sort in reverse order从列表中删除重复项并以相反顺序排序的最佳/最 Pythonic 方式
【发布时间】:2018-10-19 04:02:32
【问题描述】:

我正在尝试获取list(以下orig_list),并返回list(以下new_list):

  • 不包含重复项(即仅包含唯一元素)
  • 按倒序排列

这是我目前所拥有的,看起来……我会说“奇怪”,尽管我确信有更好的说法。对于看起来很简单的事情,我通常会因为两次使用list() 而被推迟,然后我想知道这种方法的效率。

new_list = list(reversed(sorted(list(set(orig_list)))))

问题 #1(SO 风格的问题):

下列命题正确吗?

  1. 没有比将list 转换为set 并返回更有效的方法来获取list 的唯一元素。
  2. 由于 sets are unordered in Python 必须 (1) 在删除重复项之前转换为集合,否则您无论如何都会丢失排序,并且 (2) 您必须在排序之前转换回列表。
  3. 使用 list(reversed()) 在编程上等同于使用 list.sort(reversed=True)。

问题 #2(奖励):

有没有什么方法可以在更少的操作系统中实现相同的结果,或者使用更简洁的方法?如果是这样,什么是 / 是一些例子吗?

【问题讨论】:

  • 在执行 O(n lg n) 的“降序排序”之后,可以删除 O(n) 中的重复项。这是因为,在排序之后,任何重复项都会彼此相邻。

标签: python list sorting set


【解决方案1】:
sorted(set(orig_list), reverse=True)

代码最短,效率更高,结果相同。

根据大小,先排序然后在线性时间内进行重复数据删除可能会更快,也可能不会更快,正如 user2864740 在 cmets 中建议的那样。 (这种方法的最大缺点是它完全在 Python 中,而上面的行主要在本机代码中执行。)

您的问题:

  • 您无需从集合转换为列表并返回。 sorted 接受任何可迭代对象,因此 set 符合条件,并吐出一个列表,因此不需要后转换。

  • reversed(sorted(x))等同于sorted(x, reverse=True)。您会得到相同的结果,但速度较慢 - sort 无论是前进还是后退都具有相同的速度,因此 reversed 添加了一个额外的操作,如果您从一开始就按照正确的顺序进行排序,则不需要该操作。

【讨论】:

  • 关于实施完成的地方非常好。此外,如果存在“重复数量过多”,我可能更倾向于首先确定唯一集,如图所示......但这感觉像是一个极端情况。
【解决方案2】:

您在这里有一些稍微浪费的步骤,但您的提议在很大程度上是正确的。唯一真正要做的改进是去掉所有不必要的临时lists:

new_list = sorted(set(orig_list), reverse=True)

sorted 已经将其输入转换为list(因此在传递给sorted 之前不需要listify),您可以让它直接产生输出list 反向排序(所以没有只需要生成一个list 以反向复制它)。

对 big-O 时间唯一可以想到的改进是,如果您知道数据已经排序,在这种情况下,您可以避免 O(n log n) 排序,并且 uniqify 不会丢失现有的 @ 排序顺序987654321@:

    new_list = [key for key, grp in itertools.groupby(orig_list)]

如果orig_list 是按正序排序的,您可以通过将itertools.groupby(orig_list) 更改为itertools.groupby(reversed(orig_list)) 来使这个反转的结果基本上免费。

groupby 解决方案对于最初未排序的输入并不实用,因为即使重复很常见,通过将它们作为O(n) 步骤唯一化删除它们几乎总是值得的,因为它减少了n in更昂贵的O(n log n) 排序步骤。 groupby 也是一个比较慢的工具;为每个组使用一堆临时迭代器、值的内部缓存等的实现的性质意味着它在实践中比通过setO(n) 唯一化要慢O(n),其主要优点是流方面(使其扩展到从磁盘或网络流式传输并返回的数据集,而无需长期存储任何内容,set 必须将所有内容拉入内存)。

使用sorted+groupby 的另一个原因是,如果您的数据不可散列,但具有可比性;在这种情况下,set 不是一个选项,所以唯一的选择是排序和分组。

【讨论】:

  • 很好地展示了如何对已排序的数据执行分组。由于使用了“一般”,itertools documentation on groupby 中的“通常,迭代需要已经在相同的键函数上排序”似乎乏善可陈。(在 C# 或 SQL 中,作为反例,我希望“分组依据”也可以处理未排序的数据)
  • @user2864740:是的,groupby 类似于 GNU 实用程序中的 uniq,它不是 SQL 中的组合排序+分组步骤。它不排序的事实在某些情况下实际上很有用(用于按它们出现的顺序对数据运行进行分组),这就是为什么他们说“一般”,但很像uniq,你通常需要在它前面加上如果您只想为整个可迭代对象中的每个唯一键设置一个组,则进行排序。
猜你喜欢
  • 2017-10-09
  • 2018-10-13
  • 2012-06-19
  • 2015-11-02
  • 2017-05-01
  • 2023-03-03
  • 1970-01-01
  • 2020-08-03
  • 1970-01-01
相关资源
最近更新 更多