【问题标题】:How to iterate over single tuple item in array of tuples如何迭代元组数组中的单个元组项
【发布时间】:2017-12-10 19:00:09
【问题描述】:

我有一个 Int, CustomType, OtherCustomType 元组数组。数组按元组的 Int 部分排序。

为了在正确的位置添加新元素,我编写了一个二进制搜索函数来获取插入点索引。

该函数返回一个新元组Int, Bool,其中 Bool 表示该元素是否已经存在,而 Int 是新元素第一次出现的索引,或者是第一个大于新元素。

该函数是通用编写的,它接受一个可比较类型的数组和一个相同类型的新元素作为参数,因此,很明显,我不能简单地传递我的元组数组。

一个简单的解决方案是重新组织我的数据,而不是将三个值作为元组存储在一个数组中,我可以使用三个单独的数组,每个数组仅三个值中的一个。然后我只将第一个数组传递给二分搜索函数,然后在找到的索引处对所有三个数组执行所需的操作。

但是有没有办法让我的数据组织为元组,并且只将每个元组的一个元素传递给函数,就像我们能够在比较中忽略元组的一部分,比如 if tuple == (_ ,23, _)

这里是一些示例代码:

func findInsertPoint <T: Comparable> (forElement: T, inArray: [T]) -> (Int, Bool) {
    var low = 0
    var high = inArray.count

    if forElement > inArray[high-1] {
        return (high, false)
    }
    while low < high {
        let mid = (low+high)/2
        if inArray[mid] >= forElement {
            high = mid
        } else {
            low = mid+1
        }
    }
    return(low,(inArray[low] == forElement))
}

一个 Ints 数组工作得非常好:

// index         0 1 2 3 4 5  6  7  8  9  10 11 12 13 14 15
var testArray = [1,2,5,7,8,11,12,12,12,15,19,22,22,26,52,56]

findInsertPoint(forElement: x, inArray: testArray)

// x = 17 returns (10,false)
// x = 19 returns (10,true)

但我的实际数组看起来像这样:

var testArray = [(4,"Bee",2.5),(5,"dog",1.0),(8,"dog",43.13)]

我如何传递一个仅包含每个元组第一部分的数组,而无需在每个函数调用中昂贵地创建一个实际的新数组?

可能会调用该函数:

findInsertPoint(forElement: 7 in Array: testArray.0)

这将是完美的,但我知道这不起作用。

对于只接受单一类型数组的函数调用,是否有一种 Swift 方法可以暂时忽略元组或结构的成员?

如果不是,我知道我的两种可能性是:

  1. 坚持我的定制二进制搜索,而不是上面代码中的通用搜索。
  2. 将元组分成 3 个单独的数组。

【问题讨论】:

标签: arrays swift tuples


【解决方案1】:

您可以像这样创建一个结构并在其中实现 Comparable 协议:

struct Foo: Comparable {
    let a: Int
    let b: TypeB
    let c: TypeC

    // compare according to the integers
    static func ==(lhs: Foo, rhs: Foo) -> Bool {
        return lhs.a == rhs.a
    }

    static func <(lhs: Foo, rhs: Foo) -> Bool {
        return lhs.a < rhs.a
    }
}

使用此结构,您可以调用自定义的通用排序函数,得到所需的结果,如下所示:

let foos = [Foo]()
let (position, exists) = customSort(foos)

由于您的自定义排序函数使用可比较的协议,因此它应该可以很好地与结构一起使用。

【讨论】:

  • 我不太理解这段代码的最后一部分,但将其作为一个可比较的结构是我尚未考虑的一种可能的解决方案。不过我有理由相信,在进一步的发展中,除了排序之外,还有更多可能的情况,我必须找到给定值的索引。
  • @MassMover 通过查找给定值的索引,您的意思是给定一个 Int,找到具有相同 int 值的元组吗?因为可以使用 foos.filter({ $0.a == x}) 轻松实现,其中 x 是您感兴趣的 int 值。
  • 这实际上将返回匹配元素的数组作为唯一成员,而不是元素的索引。但是高阶函数.map、.filter。和 .reduce,在问我的问题时我不知道,确实是合适的去处。
【解决方案2】:

这是我找到的解决方案:

如果你有一个类型数组,它们本身就是集合类型,并且你只想查看外部数组每个成员的某个属性,请使用 swift 集合类型的 .map 方法:

var testArray = [(4,"Bee",2.5),(5,"dog",1.0),(8,"dog",43.13)]
var onlyFirstProperty = testArray.map({$0.0}) // [4,5,8]

这样你会得到一个新数组,它只包含每个元组的第一个元素。 $0.0 是 firstMember.firstProperty 的简写语法。在我的代码中,我可以这样调用我的函数:

findInsertPoint(forElement: 7 in Array: testArray.map({$0.0}))

【讨论】:

  • 有人能告诉我们 .map 方法有多贵吗?当您使用这样的映射作为函数参数时,会迅速创建一个实际的新数组还是新数组的成员是对原始数组的引用?或者至少会应用 swift 的写时复制行为来应用值类型?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-17
  • 1970-01-01
相关资源
最近更新 更多