2017-07-06 161 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