Swift:将值A映射到B并将B映射到A

时间:2019-06-24 05:15:35

标签: swift data-structures hashmap bidirectional-relation

任务:

考虑一组值,例如0, 1, 2, 现在想象其中的两个集合以及它们之间的双射关系。

我如何在Swift中实现这一目标,将其封装在数据结构中?

说明和示例:

映射示例如下:

0 <-> 1
1 <-> 2
2 <-> 0

经典的双向哈希图不适用于此用例,因为双方的值都不唯一。

数据结构应允许从双方进行查询:

let ds = DS(...)
let ds.right(from: 1) // 2
let ds.left(from: 0) // 2

实现这种数据结构的最简单方法是什么?我可以基于哪些现有数据类型实现?

更新:

“双方的值都不唯一” 是什么? “左”侧的值在该侧是唯一的,而在“右”侧的值也是唯一的。但是,如果该值存在于一侧,则它将始终存在于另一侧。因此,值不是唯一的。

您能否举一个不唯一值的示例,以及在非唯一性情况下right(from :)和left(from :)的预期结果?

为澄清起见,左侧的所有值均为0,1,2。右侧也有0,1,2

查询示例:

ds.rightFrom(left: 2) -> 0
ds.rightFrom(left: 0) -> 1


ds.leftFrom(right: 0) -> 2
ds.leftFrom(right: 1) -> 0

3 个答案:

答案 0 :(得分:1)

从集合到自身的双射函数是permutation。如果集合由从零开始的连续整数组成,则可以将排列表示为数组。

在您的情况下,从[0,1,2]到其自身的映射由

定义
0 -> 1, 1 -> 2, 2 -> 0

将表示为数组[1, 2, 0]。然后从左到右的映射成为下标操作:

let perm = [1, 2, 0]

print(perm[1]) // 2

“从右到左”映射是反向排列,也可以表示为数组:

func inversePermution(of perm: [Int]) -> [Int]? {
    var inverse: [Int] = Array(repeating: -1, count: perm.count)
    for (idx, elem) in perm.enumerated() {
        // Check for valid entries:
        guard elem >= 0 && elem < perm.count else { return nil }
        // Check for duplicate entries:
        guard inverse[elem] == -1 else { return nil }
        // Set inverse mapping:
        inverse[elem] = idx
    }
    return inverse
}

(这只是为了演示一般思想。当然,您可以将其设置为Array扩展方法,或者使用此方法和更多方法定义Permutation类型。)

在您的示例中:

if let invPerm = inversePermution(of: perm) {
    print(invPerm) // [2, 0, 1]

    print(invPerm[2]) // 1
}

答案 1 :(得分:0)

您可以在zip(_:_:)上使用array,即

let arr1 = [0,1,2]
let arr2 = [01,2,0]

let result = Array(zip(arr1,arr2))

print(result) //Output: [(0, 1), (1, 2), (2, 0)]

答案 2 :(得分:0)

我完成的代码:

import Foundation

public struct BidirectionalMapNonUnique<Left, Right> where Left: Hashable, Right: Hashable {
    private let ltr: [Left: Right]
    public let rtl: [Right: Left]

    public init(_ ltrMapping: [Left: Right]) {
        var rtlPending = [Right: Left]()
        for (key, value) in ltrMapping {
            rtlPending[value] = key
        }
        self.ltr = ltrMapping
        self.rtl = rtlPending
    }

    public func leftFrom(right: Right) -> Left {
        return rtl[right]!
    }

    public func rightFrom(left: Left) -> Right {
        return ltr[left]!
    }
}


let example = BidirectionalMapNonUnique<Int, Int>([0:10, 1:11, 2:12])

print(example.leftFrom(right: 11)) // Prints 1
print(example.rightFrom(left: 0)) // Prints 10