【发布时间】:2018-10-04 01:44:54
【问题描述】:
我正在寻找一些函数,它可以找到使数组等于自身排列的索引。
假设p1 是一个不包含重复项的一维 Numpy 数组。假设p2 是p1 的排列(重新排序)。
我想要一个函数find_position_in_original 使得p2[find_position_in_original(p2, p1)] 与p1 相同。
例如:
p1 = np.array(['a', 'e', 'c', 'f'])
p2 = np.array(['e', 'f', 'a', 'c'])
find_position_in_permutation(p1, p2) 应该返回的位置:
[2, 0, 1, 3]
因为p2[[2, 0, 1, 3]] 与p1 相同。
您可以使用列表以蛮力的方式执行此操作:
def find_position_in_permutation(original, permutation):
original = list(original)
permutation = list(permutation)
return list(map(permutation.index, original))
但我想知道是否有更高效的算法。这个好像是O(N^2)。
当前答案的基准:
import numpy as np
from string import ascii_lowercase
n = 100
letters = np.array([*ascii_lowercase])
p1 = np.random.choice(letters, size=n)
p2 = np.random.permutation(p1)
p1l = p1.tolist()
p2l = p2.tolist()
def find_pos_in_perm_1(original, permutation):
""" My original solution """
return list(map(permutation.index, original))
def find_pos_in_perm_2(original, permutation):
""" Eric Postpischil's solution, using a dict as a lookup table """
tbl = {val: ix for ix, val in enumerate(permutation)}
return [tbl[val] for val in original]
def find_pos_in_perm_3(original, permutation):
""" Paul Panzer's solution, using an array as a lookup table """
original_argsort = np.argsort(original)
permutation_argsort = np.argsort(permutation)
tbl = np.empty_like(original_argsort)
tbl[original_argsort] = permutation_argsort
return tbl
%timeit find_pos_in_perm_1(p1l, p2l)
# 40.5 µs ± 1.13 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit find_pos_in_perm_2(p1l, p2l)
# 10 µs ± 171 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit find_pos_in_perm_3(p1, p2)
# 6.38 µs ± 157 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
【问题讨论】:
-
听起来像是搜索问题。这不是一种麻木的力量。
-
我对numpy不熟悉。我认为这些数组可用于常规 Python 函数,而不仅仅是通过 numpy.如果是这样,一个 O(n log n) 的解决方案是为一个数组中的每个元素插入一个有序对(值,索引)到平衡树中,然后在树中查找另一个数组的每个元素。 Python 的字典类型可以达到这个目的,虽然我不知道它的底层实现是什么。 (可以是一棵树,可以是一个哈希表,也可以是其他东西——无论它是什么,都可以满足您的性能需求。)
-
如果 Python 没有提供适合这种情况的内置类型,另一种解决方案是将每个数组映射到 (value, index) 的列表,然后对每个列表进行排序。两个排序后的索引表示对它们进行排序的排列。将一个排列与另一个排列组合将提供您寻求的排列。也就是两个 O(n log n) 排序和一个 O(n) 组合,所以它是 O(n log n)。
-
@EricPostpischil 是的,它们可以像我的蛮力实现一样转换为常规列表。您的第一个解决方案应该使用字典。
标签: numpy permutation