Swift:将一组值 A 映射到 B,将 B 映射到 A
Swift: map set of values A to B and B to A
任务:
考虑一组值,例如0, 1, 2
,
现在想象其中的两个集合以及它们之间的双射关系。
如何在封装在数据结构中的 Swift 中实现它?
说明和示例:
映射示例可能如下所示:
0 <-> 1
1 <-> 2
2 <-> 0
经典的双向 hashmap 不太适合这个用例,因为两边的值都不唯一。
数据结构应允许从两侧查询:
let ds = DS(...)
let ds.right(from: 1) // 2
let ds.left(from: 0) // 2
实现这种数据结构的最简单方法是什么?我的实施可以基于哪些现有数据类型?
更新:
“两边的值不唯一”是什么意思
"Left" 侧的值在该侧是唯一的,"Right" 侧的值也是如此。但是,如果值存在于一侧,它将始终存在于另一侧。因此,这些值不是唯一的。
能否举个非唯一值的例子,以及非唯一情况下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
您可以在 array
上使用 zip(_:_:)
,即
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)]
我完成的代码:
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
从集合到自身的双射函数是 permutation。如果集合由从零开始的连续整数组成,则排列可以表示为数组。
在您的例子中,从 [0, 1, 2] 到自身的映射由
定义
0 -> 1, 1 -> 2, 2 -> 0
将表示为数组 [1, 2, 0]
。然后“left-to-right”映射变为下标操作:
let perm = [1, 2, 0]
print(perm[1]) // 2
“right-to-left”映射是逆排列,也可以表示为数组:
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
}
任务:
考虑一组值,例如0, 1, 2
,
现在想象其中的两个集合以及它们之间的双射关系。
如何在封装在数据结构中的 Swift 中实现它?
说明和示例:
映射示例可能如下所示:
0 <-> 1
1 <-> 2
2 <-> 0
经典的双向 hashmap 不太适合这个用例,因为两边的值都不唯一。
数据结构应允许从两侧查询:
let ds = DS(...)
let ds.right(from: 1) // 2
let ds.left(from: 0) // 2
实现这种数据结构的最简单方法是什么?我的实施可以基于哪些现有数据类型?
更新:
“两边的值不唯一”是什么意思 "Left" 侧的值在该侧是唯一的,"Right" 侧的值也是如此。但是,如果值存在于一侧,它将始终存在于另一侧。因此,这些值不是唯一的。
能否举个非唯一值的例子,以及非唯一情况下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
您可以在 array
上使用 zip(_:_:)
,即
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)]
我完成的代码:
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
从集合到自身的双射函数是 permutation。如果集合由从零开始的连续整数组成,则排列可以表示为数组。
在您的例子中,从 [0, 1, 2] 到自身的映射由
定义0 -> 1, 1 -> 2, 2 -> 0
将表示为数组 [1, 2, 0]
。然后“left-to-right”映射变为下标操作:
let perm = [1, 2, 0]
print(perm[1]) // 2
“right-to-left”映射是逆排列,也可以表示为数组:
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
}