Arrays 如何";倒置;线性时间数组的功能性而非程序性?

Arrays 如何";倒置;线性时间数组的功能性而非程序性?,arrays,algorithm,language-agnostic,functional-programming,Arrays,Algorithm,Language Agnostic,Functional Programming,假设我有一个整数数组A,这样A[I]=j,我想“反转它”;也就是说,创建另一个整数数组B,使得B[j]=i 在任何语言中,这在线性时间内都是很容易做到的;下面是一个Python示例: def invert_procedurally(A): B = [None] * (max(A) + 1) for i, j in enumerate(A): B[j] = i return B 但是,有没有办法在线性时间内从功能上做到这一点(如在函数编程中,使用map、r

假设我有一个整数数组
A
,这样
A[I]=j
,我想“反转它”;也就是说,创建另一个整数数组
B
,使得
B[j]=i

在任何语言中,这在线性时间内都是很容易做到的;下面是一个Python示例:

def invert_procedurally(A):
    B = [None] * (max(A) + 1)
    for i, j in enumerate(A):
        B[j] = i
    return B
但是,有没有办法在线性时间内从功能上做到这一点(如在函数编程中,使用
map
reduce
,或类似的函数)

代码可能如下所示:

def invert_functionally(A):
    # We can't modify variables in FP; we can only return a value
    return map(???, A)                                       # What goes here?

如果这是不可能的,那么在进行功能编程时,最佳(最有效)的替代方案是什么?

需要
map
和3个操作的解决方案:

  • toTuples
    将数组视为元组列表
    (i,e)
    ,其中
    i
    是索引,
    e
    是数组中该索引处的元素
  • fromTuples
    从元组列表创建并加载数组
  • swap
    它接受一个元组
    (a,b)
    ,并返回
    (b,a)
  • 因此,解决方案是(用Haskellish表示法):


    在这种情况下,数组是可变的还是不可变的?一般来说,我希望可变情况与Python实现一样简单,也许除了一些类型方面的问题。我假设您对不变的场景更感兴趣

    此操作将反转索引和元素,因此了解有效数组索引的组成并对元素施加相同的约束也很重要。Haskell有一个索引约束类,名为。任何
    Ix
    类型都是有序的,并且都有一个实现来生成从一个指定索引到另一个指定索引的有序索引列表。我认为这个Haskell实现满足了您的需求

    import Data.Array.IArray
    
    invertArray :: (Ix x) => Array x x -> Array x x
    invertArray arr = listArray (low,high) newElems
      where oldElems = elems arr
            newElems = indices arr
            low = minimum oldElems
            high = maximum oldElems
    
    在引擎盖下,将指定范围内的索引与列出的元素相关联。这部分应该是线性时间,从数组中提取元素和索引的一次性操作也是线性时间

    每当输入数组的索引集和元素集不同时,一些元素将
    未定义
    ,这比Python的
    更快。我相信您可以通过在Maybe monad上实现新的
    ixa
    实例来克服
    未定义的问题


    快速补充说明:查看中的
    invPerm
    示例。它做了类似于IftRayLe>的代码,但假定前面输入数组的元素是它的索引的排列。

    @ Arnman希望它颠倒,而不是颠倒。很明显(大部分)是可能的,尽管实际的答案会根据你实际认为的“功能”而变化。您认为允许或不允许执行哪些操作?由于许多函数语言仅是,或者,最好是与列表和元组一起工作,而不是关联数组,操作将非常简单:一个<代码> MAP>代码>,其中列表中的每个成员<代码> [[(a,b)] < /代码>被处理以返回一个列表<代码> [(b,a)]。
    。数组是一个0..length-1的排列吗?@Mehrdad如果不是,那么a={2,3}或a={1,2,2}的输出是什么呢?所以你基本上假设存在一个名为
    fromTuples
    的函数,它已经满足了我们的需要,因此,答案是只调用它?@Mehrdad如果函数式语言支持数组,那么您可以非常肯定会有函数与列表进行转换。此外,它很容易实现,比如
    toTuples数组=[(i,array[i])|是的,
    toTuples
    很容易实现,但是
    fromTuples
    ?我不清楚如何在函数式语言的线性时间内实现它(因此这个问题)。如果我看不到更好的答案,我会接受,但如果我假设已经有一个库函数可以满足我的需要,那就不是一个有趣的问题。@Mehrdad-很抱歉,但在纯函数语言中,你不能破坏性地更新数组元素。相反,如果给定一个从索引类型到e元素类型。最常见的情况是从一些列表中创建一个数组。如果你想要破坏性的更新,可能没有通用的“功能性”习惯用法。Haskell可能直接在圣莫纳德,F#中这样做,因为它不纯净。我真的很喜欢你的答案。虽然它证实了Ingo所说的(+1对你们两个!),我真的很喜欢你给出了一个例子,并详细解释了发生了什么,以及它的局限性。感谢你的解释!+1就我而言,但是@Mehrdad会问你如何实现
    listary
    (这与我的回答中的
    fromTuples
    相对应)@英戈:的确,我想问,但他已经回答了这个问题!“在引擎盖下
    listary
    使用
    zipWith
    range
    。”@Jake Mitchell好吧,不用说,
    fromTuples
    需要通过两次输入列表来获得所需的数组大小,首先分配数组,然后第二次进行实际填充。在您的解决方案中,最小值、最大值和listArray基本上都是这样做的。@Ingo事后看来,这一点很明显--感谢您指出这一点。Haskell中的阵列对我来说是相对较新的领域,因此这是一次很好的学习经历:)
    import Data.Array.IArray
    
    invertArray :: (Ix x) => Array x x -> Array x x
    invertArray arr = listArray (low,high) newElems
      where oldElems = elems arr
            newElems = indices arr
            low = minimum oldElems
            high = maximum oldElems