如何在Python内置中使用swap方法而不是ai,aj=aj,ai进行排序
我有一个需要排序的对象,但尽管它有可排序属性的索引,但它不是一个如何在Python内置中使用swap方法而不是ai,aj=aj,ai进行排序,python,sorting,Python,Sorting,我有一个需要排序的对象,但尽管它有可排序属性的索引,但它不是一个列表。相反,它有一个swap方法。有办法把它分类吗 我的想法是使用一个单独的列表并跟踪排序所需的步骤,这样我就可以将每个交换应用于对象,但我不知道应该重载什么 也就是说,大多数(所有?)排序算法内部都有一个交换行,如下所示: my_list[i], my_list[j] = my_list[j], my_list[i] class SwappableList(list): def swap(self, i, j):
列表。相反,它有一个swap
方法。有办法把它分类吗
我的想法是使用一个单独的列表并跟踪排序所需的步骤,这样我就可以将每个交换应用于对象,但我不知道应该重载什么
也就是说,大多数(所有?)排序算法内部都有一个交换行,如下所示:
my_list[i], my_list[j] = my_list[j], my_list[i]
class SwappableList(list):
def swap(self, i, j):
self[i], self[j] = self[j], self[i]
s = SwappableList("bcdefahg")
print(f"before: {''.join(s)}") # prints "before: bcdefahg"
sort_with_swap(s)
print(f"after: {''.join(s)}") # prints "after: abcdefgh"
我想得到所有(I,j)
对的集合
我不想自己重新实现sort
更新:使用快速排序实现,我得到了一些有用的东西:
def partition(array, begin, end):
pivot = begin
for i in range(begin+1, end+1):
if array[i] <= array[begin]:
pivot += 1
#array[i], array[pivot] = array[pivot], array[i]
array.swap(i, pivot)
#array[pivot], array[begin] = array[begin], array[pivot]
array.swap(pivot, begin)
return pivot
def quicksort(array, begin=0, end=None):
if end is None:
end = len(array) - 1
def _quicksort(array, begin, end):
if begin >= end:
return
pivot = partition(array, begin, end)
_quicksort(array, begin, pivot-1)
_quicksort(array, pivot+1, end)
return _quicksort(array, begin, end)
class SwapSorter(list):
def __init__(self, array, obj):
super().__init__(array)
self._obj = obj
def swap(self, i, j):
if i == j: return
print("swapping:",i,j)
self[i], self[j] = self[j], self[i]
self._obj.swap(i,j)
ss = SwapSorter(array, obj)
quicksort(ss)
print("sorted:")
print(ss)
print(ss._obj)
def分区(数组、开始、结束):
枢轴=开始
对于范围内的i(开始+1,结束+1):
如果数组[i]=结束:
返回
pivot=分区(数组、开始、结束)
_快速排序(数组、开始、pivot-1)
_快速排序(数组,轴+1,结束)
返回\u快速排序(数组、开始、结束)
类交换器(列表):
定义初始化(自、数组、对象):
super().\uuuu init\uuuu(数组)
自身。_obj=obj
def交换(自身、i、j):
如果i==j:返回
打印(“交换:”,i,j)
self[i],self[j]=self[j],self[i]
自交换(i,j)
ss=SwapSorter(阵列,obj)
快速排序(ss)
打印(“已排序:”)
印刷品(ss)
打印(ss.\U obj)
但是(我想)我只想使用内置排序而不是我自己的排序。。。或者,这只是一种常见的做法,您可以自己进行分类吗?实际答案是
听起来你所做的很好,但我很好奇,并根据你所问的精神想出了一个答案。有关动机及其工作原理,请参见后面的章节,但切中要害:
def sort_with_swap(mylist):
# Source locations of items (satifies: source_index = source_indices[dest_index])
source_indices = sorted(range(len(mylist)), key=lambda i: mylist[i])
# Destination locations of items (satisfies: dest_index = destination_indices[source_index])
destination_indices = [None] * len(source_indices)
for dest_index, source_index in enumerate(source_indices):
destination_indices[source_index] = dest_index
# Perform the swaps
for dest_index, source_index in enumerate(source_indices):
# Nothing to do if src==dest (although code below actually works if you remove this)
if source_index == dest_index:
continue
# Swap the source item into the correct destination
mylist.swap(source_index, dest_index)
# Update the index lists for the new location of the item that had been in the destination
old_dest_at_dest_index = destination_indices[dest_index]
source_indices[old_dest_at_dest_index] = source_index
destination_indices[source_index] = old_dest_at_dest_index
# These two updates are not necessary but leave index lists in correct state at the end
# source_indices[dest_index] = dest_index
# destination_indices[dest_index] = dest_index
测试
您可以尝试以下功能:
my_list[i], my_list[j] = my_list[j], my_list[i]
class SwappableList(list):
def swap(self, i, j):
self[i], self[j] = self[j], self[i]
s = SwappableList("bcdefahg")
print(f"before: {''.join(s)}") # prints "before: bcdefahg"
sort_with_swap(s)
print(f"after: {''.join(s)}") # prints "after: abcdefgh"
动机
我认为您的问题建议跟踪排序时交换的内容,并直接对列表执行这些交换。正如你所看到的,我采取了一种不同的策略:允许整个排序在索引列表上进行,然后在此基础上进行交换。这有几个好处:
这样就不那么麻烦了,因为要跟踪这类任务发生时正在执行的操作,您必须等待两个任务,检查它们是否真的是交换,然后将它们重新缝合在一起
如果排序实现执行与交换不同的操作(例如,排列三个元素,或将透视项保留在单独的位置),它不会中断
它减少了列表式结构上的掉期数量,听起来可能很昂贵
工作原理
这是我第一次天真地尝试我的想法:
# Warning: doesn't work
def sort_with_swap_naive(mylist):
source_indices = sorted(range(len(mylist)), key=lambda i: mylist[i])
for dest_index, source_index in enumerate(source_indices):
mylist.swap(source_index, dest_index)
这很简单:
我们对索引列表而不是原始列表进行排序。例如,对于列表('bcdefahg')
,您会得到[5,0,1,2,3,4,7,6]
我们浏览索引列表,并将每个项交换到正确的位置
不幸的是,这个简单的版本不起作用。首先,如果您通过最后两项('g'
和'h'
)跟踪交换,您会发现我们将它们交换到正确的位置,并立即将它们交换回来!对于列表的置换部分,问题更为复杂,但潜在的问题是相同的
问题是:我们正在使用off源代码索引来确定要交换哪些元素,但是当我们浏览列表时,它就不同步了。为了解决这个问题,我们还需要在进行掉期交易时对其进行更新。事实证明,为了有效地实现这一点,我们需要一个包含相反映射的列表,即目的地索引列表。要查看需要更新的内容,请查看交换元素0和5前后的原始列表:
mylist = ['b', 'c', 'd', 'e', 'f', 'a', 'h', 'g']
sources = [5, 0, 1, 2, 3, 4, 7, 6]
destinations = [1, 2, 3, 4, 5, 0, 7, 6]
# Swap item at 0 with item at 5
mylist = ['a', 'c', 'd', 'e', 'f', 'b', 'h', 'g']
# updates: ^ ^
sources = [0, 5, 1, 2, 3, 4, 7, 6]
# updates: ^ ^
destinations = [0, 2, 3, 4, 5, 1, 7, 6]
# updates: ^ ^
正如您所看到的(可能!),要更新的关键内容是在交换前立即位于目标索引(即位于0的“b”)的项。实际答案
听起来你所做的很好,但我很好奇,并根据你所问的精神想出了一个答案。有关动机及其工作原理,请参见后面的章节,但切中要害:
def sort_with_swap(mylist):
# Source locations of items (satifies: source_index = source_indices[dest_index])
source_indices = sorted(range(len(mylist)), key=lambda i: mylist[i])
# Destination locations of items (satisfies: dest_index = destination_indices[source_index])
destination_indices = [None] * len(source_indices)
for dest_index, source_index in enumerate(source_indices):
destination_indices[source_index] = dest_index
# Perform the swaps
for dest_index, source_index in enumerate(source_indices):
# Nothing to do if src==dest (although code below actually works if you remove this)
if source_index == dest_index:
continue
# Swap the source item into the correct destination
mylist.swap(source_index, dest_index)
# Update the index lists for the new location of the item that had been in the destination
old_dest_at_dest_index = destination_indices[dest_index]
source_indices[old_dest_at_dest_index] = source_index
destination_indices[source_index] = old_dest_at_dest_index
# These two updates are not necessary but leave index lists in correct state at the end
# source_indices[dest_index] = dest_index
# destination_indices[dest_index] = dest_index
测试
您可以尝试以下功能:
my_list[i], my_list[j] = my_list[j], my_list[i]
class SwappableList(list):
def swap(self, i, j):
self[i], self[j] = self[j], self[i]
s = SwappableList("bcdefahg")
print(f"before: {''.join(s)}") # prints "before: bcdefahg"
sort_with_swap(s)
print(f"after: {''.join(s)}") # prints "after: abcdefgh"
动机
我认为您的问题建议跟踪排序时交换的内容,并直接对列表执行这些交换。正如你所看到的,我采取了一种不同的策略:允许整个排序在索引列表上进行,然后在此基础上进行交换。这有几个好处:
这样就不那么麻烦了,因为要跟踪这类任务发生时正在执行的操作,您必须等待两个任务,检查它们是否真的是交换,然后将它们重新缝合在一起
如果排序实现执行与交换不同的操作(例如,排列三个元素,或将透视项保留在单独的位置),它不会中断
它减少了列表式结构上的掉期数量,听起来可能很昂贵
工作原理
这是我第一次天真地尝试我的想法:
# Warning: doesn't work
def sort_with_swap_naive(mylist):
source_indices = sorted(range(len(mylist)), key=lambda i: mylist[i])
for dest_index, source_index in enumerate(source_indices):
mylist.swap(source_index, dest_index)
这很简单:
我们对索引列表而不是原始列表进行排序。例如,对于列表('bcdefahg')
,您会得到[5,0,1,2,3,4,7,6]
我们浏览索引列表,并将每个项交换到正确的位置
不幸的是,这个简单的版本不起作用。首先,如果您通过最后两项('g'
和'h'
)跟踪交换,您会发现我们将它们交换到正确的位置,并立即将它们交换回来!对于列表的置换部分,问题更为复杂,但潜在的问题是相同的
问题是:我们正在使用off源代码索引来确定要交换哪些元素,但是当我们浏览列表时,它就不同步了。为了解决这个问题,我们还需要在进行掉期交易时对其进行更新。事实证明,要做到这一点