我們?cè)赟wift開(kāi)發(fā)過(guò)程中經(jīng)常會(huì)碰到數(shù)組去重的情況,基本數(shù)據(jù)類(lèi)型數(shù)組的去重比較好辦,那如果碰到model模型類(lèi)的數(shù)組去重,又怎么進(jìn)行科學(xué)合理的處理呢?通常對(duì)model進(jìn)行去重,要依賴其某個(gè)屬性,一般是一個(gè)唯一ID,然后通過(guò)該ID來(lái)進(jìn)行判斷是否有重復(fù)的模型。
比如有個(gè)模型AModel如下:
class AModel {
var name: String?
var img: String?
var aID: Int = 0 //唯一ID
}
普通處理
AModel的屬性中有可以用來(lái)判斷唯一性的aID,因此我們?cè)趯?duì)裝著AModel類(lèi)型的數(shù)組[AModel]進(jìn)行去重時(shí)可以這么處理:
func handleFilterArray(arr:[AModel]) -> [AModel] {
var temp = [AModel]() //存放符合條件的model
var idxArr = [Int]() //存放符合條件model的aID,用來(lái)判斷是否重復(fù)
for model in arr {
let index = model.aID //遍歷獲得model的唯一標(biāo)識(shí)aID
if !idxArr.contains(index){ //如果該aID已經(jīng)添加過(guò),則不再添加
idxArr.append(index)
temp.append(model) //如果該aID沒(méi)有添加過(guò),則添加到temp數(shù)組中
}
}
return temp //最終返回的數(shù)組中已經(jīng)篩選掉重復(fù)aID的model
}
泛型處理
如果我們需要處理不同model類(lèi)型的數(shù)組,那我們是否可以將上面的方法寫(xiě)成一個(gè)通用的方法,比如下面這樣用Swift的泛型來(lái)處理:
//T為不同model的類(lèi)型
func handleFilterArray(arr:[T]) -> [T] {
//具體實(shí)現(xiàn)
}
可是我們碰到一個(gè)問(wèn)題,你用泛型來(lái)寫(xiě)的話,這個(gè)泛型無(wú)法確定你不同模型中需要判斷的那個(gè)ID是什么,因?yàn)锽Model的唯一ID是bID,CModel的唯一ID是cID,因此我們?cè)趺床拍馨堰@個(gè)不同的標(biāo)識(shí)符給帶到這個(gè)函數(shù)中來(lái)呢,下面先來(lái)看方法一,利用protocol來(lái)處理:
protocol arrayFilterable {
var identifer:Int {get} //該只讀屬性用來(lái)獲取不同model的不同唯一ID
}
extension AModel: arrayFilterable{
var identifer: Int{
return aID //AModel則返回aID
}
}
extension BModel: arrayFilterable{
var identifer: Int{
return bID //BModel則返回bID
}
}
然后我們的處理方法就可以寫(xiě)成這樣:
func handleFilterArray<T:arrayFilterable>(arr:[T]) -> [T] {
var temp = [T]()
var idxArr = [Int]()
for model in arr {
let index = model.identifer //通過(guò)identifer來(lái)判斷不同模型是否有重復(fù)數(shù)據(jù)
if !idxArr.contains(index){
idxArr.append(index)
temp.append(model)
}
}
return temp
}
更合理的泛型處理
但以上的方法是不是還是顯得有點(diǎn)不那么高效,畢竟需要每個(gè)模型都遵循arrayFilterable協(xié)議,而且顯得可擴(kuò)展性一般,如果有一個(gè)DModel用來(lái)判斷唯一性的不是ID,而是一個(gè)字符串呢,我們?cè)賮?lái)看看方法二,利用泛型結(jié)合Swift數(shù)組的高階函數(shù)map來(lái)處理:
//直接給Array擴(kuò)展一個(gè)方法
extension Array {
//該函數(shù)的參數(shù)filterCall是一個(gè)帶返回值的閉包,傳入模型T,返回一個(gè)E類(lèi)型
func handleFilter<E: Equatable>(_ filterCall: (T) -> E) -> [T] {
var temp = [T]()
for model in self {
//調(diào)用filterCall,獲得需要用來(lái)判斷的屬性E
let identifer = filterCall(model)
//此處利用map函數(shù) 來(lái)將model類(lèi)型數(shù)組轉(zhuǎn)換成E類(lèi)型的數(shù)組,以此來(lái)判斷
identifer 是否已經(jīng)存在,如不存在則將model添加進(jìn)temp
if !temp.map( { filterCall($0) } ).contains(identifer) {
temp.append(model)
}
}
return temp
}
}
上面?zhèn)魅腴]包filterCall的返回值E,就是模型的屬性中用來(lái)判斷唯一型的那個(gè)屬性,需要遵循Equatable,才能使用數(shù)組的contains函數(shù)來(lái)判斷是否已經(jīng)存在。
如果AModel用來(lái)判斷唯一性的不是aID,而是name屬性,則一個(gè)裝著有好多重復(fù)AModel的數(shù)組AModelArray可以這么調(diào)用這個(gè)函數(shù):
let filterArray = AModelArray.handleFilter( { $0.name } )
$0.name即filterCall閉包的返回值,用來(lái)判斷數(shù)組中model唯一性的依據(jù)。
結(jié)語(yǔ)
通過(guò)這個(gè)小應(yīng)用,可以看出Swift中強(qiáng)大的泛型特性能夠讓我們根據(jù)不同的需求,來(lái)編寫(xiě)靈活強(qiáng)大的函數(shù)和類(lèi)型,讓我們避免重復(fù)冗余的代碼,更加快速高效的達(dá)到應(yīng)用目的。