【问题标题】:Inverting permutations in Python在 Python 中反转排列
【发布时间】:2012-02-07 23:39:33
【问题描述】:

我是编程新手,我正在尝试编写一个 Python 函数来使用以下代码查找 {1,2,3,...,n} 上的逆排列:

def inv(str):
    result = []
    i = list(str).index(min(list(str)))
    while min(list(str)) < len(list(str)) + 1:
        list(str)[i : i + 1] = [len(list(str)) + 1]
        result.append(i + 1)
    return result

但是,当我尝试使用该函数时,inv('&lt;mypermutation&gt;') 返回[]。我错过了什么吗? Python 是否因为某些我不理解的语法原因跳过了我的 while 循环?我对我认为的主题的 google 和 stackoverflow 搜索都没有返回任何有用的信息。

【问题讨论】:

  • 不要命名变量str;它是内置的。
  • “如有疑问,请打印更多内容。”
  • 我尝试将“str”重命名为“permutation”,但仍然返回“[]”。还有其他提示吗?
  • @Fingolfin:哦,等等,你是在字面上执行inv('&lt;mypermutation&gt;')吗?然后,while 条件将字符串与整数进行比较,根据您使用的 Python 版本,该整数可能具有 False 结果。例如,在 Python 3 中,您会收到错误消息。
  • Fingolfin,我认为您需要展示一个未经修改的文字示例,说明您如何调用此函数来帮助人们解决这个问题。

标签: python permutation


【解决方案1】:

其他答案是正确的,但值得一提的是,使用 numpy 有一个性能更高的替代方案:

inverse_perm = np.argsort(permutation)

编辑:下面的第四个函数更快。

计时码:

def invert_permutation_list_scan(p):
    return [p.index(l) for l in range(len(p))]

def invert_permutation_list_comp(permutation):
    return [i for i, j in sorted(enumerate(permutation), key=lambda i_j: i_j[1])]

def invert_permutation_numpy(permutation):
    return np.argsort(permutation)

def invert_permutation_numpy2(permutation):
    inv = np.empty_like(permutation)
    inv[permutation] = np.arange(len(inv), dtype=inv.dtype)
    return inv

x = np.random.randn(1000)
perm = np.argsort(x)
permlist = list(perm)
assert np.array_equal(invert_permutation_list_scan(permlist), invert_permutation_numpy(perm))
assert np.array_equal(invert_permutation_list_comp(perm), invert_permutation_numpy(perm))
assert np.array_equal(invert_permutation_list_comp(perm), invert_permutation_numpy2(perm))
%timeit invert_permutation_list_scan(permlist)
%timeit invert_permutation_list_comp(perm)
%timeit invert_permutation_numpy(perm)
%timeit invert_permutation_numpy2(perm)

结果:

82.2 ms ± 7.28 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
479 µs ± 9.19 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
18 µs ± 1.17 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
4.22 µs ± 388 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

【讨论】:

  • 好吧,如果你追求速度,那么你可以做更少的工作:. ``` def invert_permutation_numpy2(permutation): x = np.empty_like(permutation) x[permutation] = np.arange(len(permutation), dtype=permutation.dtype) return x ``` 。在迷你基准上,它击败了 numpy 排序 10-20 倍
  • @VF1 不错。我已经编辑了答案以包含这个更快的功能。
  • 我认为np.arange(len(permutation))[np.argsort(permutation)] 等于np.argsort(permutation)
  • 好收获。固定!
【解决方案2】:

如果你只想要逆排列,你可以使用

def inv(perm):
    inverse = [0] * len(perm)
    for i, p in enumerate(perm):
        inverse[p] = i
    return inverse

perm = [3, 0, 2, 1]
print(inv(perm))
for i in perm:
    print(inv(perm)[i])

[1, 3, 2, 0]
0
1
2
3

【讨论】:

    【解决方案3】:

    我相信反转排列的最佳方法 perm

    pinv = sorted(range(len(perm)), key=perm.__getitem__)
    

    这避免了对.index() 的重复调用(如 SeF 的回答),这可能不是很有效(二次时间复杂度,而排序应该只需要 O(n log n))。

    但是请注意,无论输入是否是 {0,1,...,n-1} 的排列,这都会产生 {0,1,...n-1} 的排列} 或 {1,2,...,n} (后者是问题中所述)。如果输出应该是 {1,2,...,n} 的排列,则结果的每个元素都必须增加一个,例如,像这样:

    pinv = [i+1 for i in sorted(range(len(perm)), key=perm.__getitem__)]
    

    【讨论】:

      【解决方案4】:

      如果我有这个错误,请纠正我,但我认为当我将str 更改为列表时,我的代码出现了问题:str 是一个字符串,list(str) 是一个字符串元素列表。但是,由于字符串元素不能在数字上与数字进行比较,因此代码无法产生结果([] 除外)。

      【讨论】:

        【解决方案5】:

        “功能风格”版本:

        def invert_permutation(permutation):
            return [i for i, j in sorted(enumerate(permutation), key=lambda (_, j): j)]
        

        基本上,按排列中的值 j 对排列的索引 i 进行排序会产生所需的逆。

        p = [2, 1, 5, 0, 4, 3]
        
        invert_permutation(p)
        # [3, 1, 0, 5, 4, 2]
        
        # inverse of inverse = identity
        invert_permutation(invert_permutation(p)) == p
        # True
        

        【讨论】:

          【解决方案6】:

          由于这里还没有人推荐它,我认为应该提到 SymPy 有一个 entire combinatorics module,有一个 Permutation 类:

          from sympy.combinatorics import Permutation
          o = [3, 0, 2, 1]
          p = Permutation(o)
          inv = p.__invert__()
          print(inv.array_form) # [1, 3, 2, 0]
          

          使用 SymPy 类可以让您访问大量其他有用的方法,例如比较等价排列与 ==

          您可以阅读sympy.combinatorics.Permutation源代码here

          除此之外,我会在此页面上使用np.arangeargsort 推荐the answer

          【讨论】:

            【解决方案7】:

            也许有更短的方法:

            def invert(p):
                return [p.index(l) for l in range(len(p))] 
            

            这样:

            perm = [3, 0, 2, 1]; print(invert(perm))
            

            返回

            [1,3,2,0]

            【讨论】:

            • 请注意,这是低效的,时间为 O(len(p) ^ 2)。
            猜你喜欢
            • 2017-06-13
            • 2014-03-19
            • 1970-01-01
            • 2019-06-13
            • 2015-04-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-03-09
            相关资源
            最近更新 更多