我們在Swift開發(fā)過程中經(jīng)常會碰到數(shù)組去重的情況结缚,基本數(shù)據(jù)類型數(shù)組的去重比較好辦,那如果碰到model模型類的數(shù)組去重走孽,又怎么進(jìn)行科學(xué)合理的處理呢尺棋?通常對model進(jìn)行去重,要依賴其某個屬性莽使,一般是一個唯一ID锐极,然后通過該ID來進(jìn)行判斷是否有重復(fù)的模型。
比如有個模型AModel如下:
class AModel {
var name: String?
var img: String?
var aID: Int = 0 //唯一ID
}
普通處理
AModel的屬性中有可以用來判斷唯一性的aID芳肌,因此我們在對裝著AModel類型的數(shù)組[AModel]進(jìn)行去重時可以這么處理:
func handleFilterArray(arr:[AModel]) -> [AModel] {
var temp = [AModel]() //存放符合條件的model
var idxArr = [Int]() //存放符合條件model的aID灵再,用來判斷是否重復(fù)
for model in arr {
let index = model.aID //遍歷獲得model的唯一標(biāo)識aID
if !idxArr.contains(index){ //如果該aID已經(jīng)添加過,則不再添加
idxArr.append(index)
temp.append(model) //如果該aID沒有添加過亿笤,則添加到temp數(shù)組中
}
}
return temp //最終返回的數(shù)組中已經(jīng)篩選掉重復(fù)aID的model
}
泛型處理
如果我們需要處理不同model類型的數(shù)組翎迁,那我們是否可以將上面的方法寫成一個通用的方法,比如下面這樣用Swift的泛型來處理:
//T為不同model的類型
func handleFilterArray(arr:[T]) -> [T] {
//具體實現(xiàn)
}
可是我們碰到一個問題净薛,你用泛型來寫的話鸳兽,這個泛型無法確定你不同模型中需要判斷的那個ID是什么,因為BModel的唯一ID是bID罕拂,CModel的唯一ID是cID揍异,因此我們怎么才能把這個不同的標(biāo)識符給帶到這個函數(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來判斷不同模型是否有重復(fù)數(shù)據(jù)
if !idxArr.contains(index){
idxArr.append(index)
temp.append(model)
}
}
return temp
}
更合理的泛型處理
但以上的方法是不是還是顯得有點(diǎn)不那么高效衷掷,畢竟需要每個模型都遵循arrayFilterable協(xié)議,而且顯得可擴(kuò)展性一般柿菩,如果有一個DModel用來判斷唯一性的不是ID戚嗅,而是一個字符串呢,我們再來看看方法二枢舶,利用泛型結(jié)合Swift數(shù)組的高階函數(shù)map來處理:
//直接給Array擴(kuò)展一個方法
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添加進(jìn)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屬性距帅,則一個裝著有好多重復(fù)AModel的數(shù)組AModelArray可以這么調(diào)用這個函數(shù):
let filterArray = AModelArray.handleFilter( { $0.name } )
$0.name即filterCall閉包的返回值,用來判斷數(shù)組中model唯一性的依據(jù)括堤。
結(jié)語
通過這個小應(yīng)用碌秸,可以看出Swift中強(qiáng)大的泛型特性能夠讓我們根據(jù)不同的需求,來編寫靈活強(qiáng)大的函數(shù)和類型悄窃,讓我們避免重復(fù)冗余的代碼哮肚,更加快速高效的達(dá)到應(yīng)用目的。