【问题标题】:Efficient way to check if the last element in a row (in a list of lists) is found in another list?检查是否在另一个列表中找到行中的最后一个元素(在列表列表中)的有效方法?
【发布时间】:2017-02-05 20:51:47
【问题描述】:

我目前有一个大约 9 列和 5000 行的列表(我们将其命名为“大”),并且还在不断增长。我有另一个列表(我们将其命名为“小”),其中包含大约 3000 个元素。我的目标是返回 big[8] 可以在 small 中找到的每一行。结果将存储在列表列表中。

我使用了列表理解,它一直在返回正确的输出,但它对我的需求来说效率太低了。处理这 5000 行需要几秒钟的时间(通常大约 6.5 秒,而且列表越大效率越差),并且需要能够快速处理数十万行。

我写的列表理解是:

results = [row for row in big if row[8] in small]

列表列表的示例数据(大):

[[23.4, 6.8, 9.0, 13.0, 4.0, 19.0, 2.5, 7.6, 1472709600000], 
[32.1, 15.5, 17.7, 21.7, 12.7, 27.7, 11.2, 16.3, 1472882400000], 
[40.8, 24.2, 26.4, 30.4, 21.4, 36.4, 19.9, 25.0, 1473055200000], 
[49.5, 32.9, 35.1, 39.1, 30.1, 45.1, 28.6, 33.7, 1473228000000], 
[58.2, 41.6, 43.8, 47.8, 38.8, 53.8, 37.3, 42.4, 1473400800000]]

列表样本数据(小):

[1472709600000, 1473055200000]

期望的输出(结果):

[[23.4, 6.8, 9.0, 13.0, 4.0, 19.0, 2.5, 7.6, 1472709600000], 
[40.8, 24.2, 26.4, 30.4, 21.4, 36.4, 19.9, 25.0, 1473055200000]]

有没有更有效的方法来返回在另一个列表中找到其最后一个元素的每一行?

【问题讨论】:

  • 试试这个代码:results = [row for row in big if row[-1] in small] 这将有助于动态长度列表。
  • @AjaySreeram 您的回答与内存和时间方面的任何效率无关。

标签: python performance list


【解决方案1】:

对您的小列表进行二进制搜索,这会将时间复杂度降低到 O(log n)。

smallset = sort(small)
def binarySearch(x):
   #implement binary search
   pass
results = [row for row in big if binarySearch(row[8])]

【讨论】:

  • 虽然这段代码可能有助于解决问题,但它并没有解释为什么和/或如何回答问题。提供这种额外的背景将显着提高其长期教育价值。请edit您的答案添加解释,包括适用的限制和假设。
【解决方案2】:

一种快速简便的方法是创建一个以 8 列项为键的字典。下面是一个代码sn-p。

big_dict = {}
for list in big:
    big_dict[list[-1]] = list
output_list = []
for element in small:
    output_list.append(big_dict[element])

【讨论】:

  • 我真的很喜欢这种方法。使用这个,有没有一种方法可以返回一个列表列表,其中包含那些在 small 中找不到最后一个元素的行?
  • @Hunter Corry 是的,你可以这样做。 big_dict = {} for list in big: big_dict[list[-1]] = list output_list_1 = [] output_list_2 = [] for element_x in small: output_list_1.append(big_dict.pop(element_x)) for element in big_dict.values(): output_list_2.append(element)
  • 谢谢!这种方法效率稍高一些,但阅读起来有点困难。出于这个原因,我将使用@John Zwinck 推荐的内容,以便其他人能够更轻松地跟进。如果随着行数的增加遇到更多的效率问题,我肯定会切换到这种方法以从代码中挤出最后一点性能。
  • 如果两个大列表的最后一个元素相同怎么办?不工作
  • 这是一个很好的观点@Jal,但幸运的是,在我的使用中,最后一个元素实际上是 SQL 表的主键,所以最后一个元素将始终是唯一的。
【解决方案3】:

您可以通过使用集合轻松消除每次迭代中small 的线性搜索:

smallset = set(small)
results = [row for row in big if row[8] in smallset]

【讨论】:

  • 哦,当然!我试图弄清楚如何制作大系列和小系列并进行比较,或者只是制作大系列。完全掩盖了制作小型套装的效率。非常感谢你的帮助!进行此更改使我在 5000 行上的效率提高了 180 倍。
  • 180 倍令人印象深刻。你能发布你的结果吗?
  • 为什么使用 set 会更快?我不明白。
  • @Jal 在这篇文章中选择的答案很好地解释了这一点:link
  • @SSNR 5000 行的运行时间从大约 6.5 秒减少到大约 0.035 秒,而 10,000 行只需要 0.049 秒
猜你喜欢
  • 2021-08-24
  • 2022-01-06
  • 2021-04-30
  • 1970-01-01
  • 2020-07-07
  • 2012-08-01
  • 1970-01-01
  • 2023-03-22
  • 2018-05-13
相关资源
最近更新 更多