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