python - How can I do an efficient in-place sort on an arbitrary indexable collection?
问题描述
Question
How can I use Python's inbuilt sort (or similar) to do an in-place sort on a arbitrary collection (which supports __len__
, __getitem__
and __setitem__
methods)?
Background
The question arose from considering the following problem (somewhat related to this question). Suppose that I have two large lists of equal length:
hours = [20, 21, 18, 18, 19]
minutes = [15, 14, 13, 12, 11]
(in this example representing the times 20:15, 21:14, etc).
I want to sort these lists together in-place as pairs of values from the two lists (such as those retured by zip
), to give:
hours = [18, 18, 19, 20, 21]
minutes = [12, 13, 11, 15, 14]
One could implement this by encapsulating both lists into a custom collection that uses paired values when indexing, and then sorting that collection.
Here's the collection class:
class Times:
def __init__(self, hours, minutes):
if len(hours) != len(minutes):
raise ValueError('lists must be of same length')
self.hours = hours
self.minutes = minutes
def __getitem__(self, i):
return (self.hours[i], self.minutes[i])
def __setitem__(self, i, vals):
self.hours[i], self.minutes[i] = vals
def __len__(self):
return len(self.hours)
We can sort the underlying lists in a memory-efficient way by doing an in-place sort on the top-level collection. But the following example uses a CPU-inefficient sorting algorithm.
def bubble_sort(x):
n = len(x)
for last in range(n-1, 0, -1):
for pos in range(last):
if x[pos] > x[pos+1] :
x[pos], x[pos+1] = x[pos+1], x[pos]
hours = [20, 21, 18, 18, 19]
minutes = [15, 14, 13, 12, 11]
times = Times(hours, minutes)
bubble_sort(times)
print(hours) # [18, 18, 19, 20, 21]
print(minutes) # [12, 13, 11, 15, 14]
Alternatively, we can use Python's more efficient builtin sorted
, but then we are allocating more memory because it is not sorting in-place.
hours = [20, 21, 18, 18, 19]
minutes = [15, 14, 13, 12, 11]
times = Times(hours, minutes)
for i, v in enumerate(sorted(times)):
times[i] = v
print(hours) # [18, 18, 19, 20, 21]
print(minutes) # [12, 13, 11, 15, 14]
So it would be desirable to be able to do an in-place sort using Python's inbuilt sort (or something similar). Here is a failed attempt to use list.sort
on something other than a list -- it isn't supported:
>>> list.sort(times)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor 'sort' requires a 'list' object but received a 'instance'
How can this be done?
解决方案
推荐阅读
- maven-3 - 如何使用 ${} 访问 POM 文件中的 POM 文件目录
- javascript - 如何将从 api 接收到的数据发送到我设计的 html 页面
- django - Celery 在被主管运行后无法从 env 文件中读取值
- powershell - 如何在安装在 NTFS 文件夹中的驱动器上使用 GET-PSDrive 获取信息,而无需驱动器号
- java - 为什么我在尝试创建新的 JavaFx 项目时收到警告?
- html - 如果我使用最大宽度,为什么要使用宽度?
- c++ - 为什么 std::integral 用 type_trait 定义而不用 std::numeric_limits 定义?
- html - 我想使用 VBA 打开我在 excel 中列出的网站 URL 列表并从特定对象返回一个值
- windows - 将已安装的程序转移到新的 Windows PC - 移动所有依赖项
- javascript - 无法在 javascript 中导入图像。模块解析失败:意外字符 '�' (1:0)