2017-07-06 158 views
0

我有一个元组数组(Int,CustomType,OtherCustomType)。该数组按元组的Int部分排序。swift - 遍历元组数组中的单个元组项目

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

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

该函数是通用编写的,它需要一个可比较类型的数组和一个与参数类型相同的新元素,显然,我不能简单地传递我的元组数组。

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

但有没有办法让我的数据组织为元组,并且只传递每个元组的一个元素到函数中,就像我们能够忽略比较中的元组的部分,如“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)) 
} 

整数数组工作完全正常:

// 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) 

...将是完美的,但我知道这是行不通的。

因此,TL; DR:是否有一种迅速的方法来临时忽略元组或结构的一个函数调用,只接受单一类型的数组?

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

  1. 坚持我taylored二进制搜索(而不是从上面的代码的一般之一)
  2. 鸿沟解析成3个独立的阵列。
+0

通常的方法是传递一个自定义比较函数,这里:https://stackoverflow.com/a/26679191/1187415,类似于现有的排序方法,如https://developer.apple.com/documentation/swift/array/2296815-sorted。 –

+0

“我可以使用3个独立的数组,每个数组只有3个值中的一个。”大多数肯定不会这样做。那种方式就是疯狂。 – Alexander

+0

你可以给我们一些可编辑的样本数据来工作吗? – Alexander

回答

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})) 
+0

有人可以告诉.map方法是多么昂贵吗?当你使用这样一个映射作为函数参数时,swift会创建一个实际的新数组还是新数组的成员是对原始数组的引用?或者至少swift的写时复制行为适用于值类型? – MassMover

0

您可以创建一个结构和实现它像这样可比协议:

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) 

由于您的自定义排序功能使用可比较的协议,它应该适用于结构。

+0

我不太明白最后一个这段代码的一部分,但使它成为一个可比较的结构是我还没有想过的一种可能的解决方案。然而,我有理由相信,在进一步的发展中,除了排序我必须找到给定值的索引之外,还有更多可能的情况。 – MassMover

+0

@MassMover通过查找给定值的索引,是否给出了一个Int,找到具有相同int值的元组?因为使用'foos.filter({$ 0.a == x})'可以很容易地实现,其中'x'是您感兴趣的int值。 – mohak

+0

这实际上会返回匹配元素的数组,作为只有成员,而不是元素的索引。但是高阶函数.map,.filter。当我问及我的问题时,我对此一无所知,这确实是一个正确的选择。 – MassMover