Swift4字典和集合的新特性

Swift4中的字典和集合在這些方面變得更好

寫在前面

在最新版本的Swift中丧鸯,dictionaries和sets新增了很多行為方法和初始化方法惊窖,讓一些常見的任務(wù)變得異常簡單突诬。諸如組合漫雷、過濾和transform值操作可以用一步完成颂龙,讓使用者可以寫出更高效和簡潔的代碼习蓬。

本篇博客將使用雜貨鋪中的商品作為例子演示這些新功能纽什。GroceryItem結(jié)構(gòu)體,由名字和部門組成躲叼,作為本例的數(shù)據(jù)類型稿湿。

struct GroceryItem: Hashable {
    var name: String
    var department: Department

    enum Department {
        case bakery, produce, seafood
    }

    static func ==(lhs: GroceryItem, rhs: GroceryItem) -> Bool {
        return (lhs.name, lhs.department) == (rhs.name, rhs.department)
    }

    var hashValue: Int {
        // Combine the hash values for the name and department
        return name.hashValue << 2 | department.hashValue
    }
}

// Create some groceries for our store:
let ?? = GroceryItem(name: "Apples", department: .produce)
let ?? = GroceryItem(name: "Bananas", department: .produce)
let ?? = GroceryItem(name: "Croissants", department: .bakery)
let ?? = GroceryItem(name: "Salmon", department: .seafood)
let ?? = GroceryItem(name: "Grapes", department: .produce)
let ?? = GroceryItem(name: "Bread", department: .bakery)
let ?? = GroceryItem(name: "Shrimp", department: .seafood)

let groceries = [??, ??, ??, ??, ??, ??, ??]

后面的例子將圍繞著groceries數(shù)組展示。

用Key值對原數(shù)組進(jìn)行分組

字典擁有了一個(gè)新的初始化函數(shù)押赊,可以將一系列值按照Key值進(jìn)行分組饺藤。下面展示使用該初始化方法根據(jù)GroceryItem的department進(jìn)行分組的一個(gè)小例子。

<div align=center>



</div>

在老版本的Swift中流礁,用戶可以使用如下的代碼完成上述任務(wù)涕俗。

// Swift <= 3.1
var grouped: [GroceryItem.Department: [GroceryItem]] = [:]
for item in groceries {
    if grouped[item.department] != nil {
        grouped[item.department]!.append(item)
    } else {
        grouped[item.department] = [item]
    }
}

這一過程需要使用type annotations、手動(dòng)循環(huán)并且需要檢查departement是否已經(jīng)存在了神帅。

在Swift4中再姑,用戶可以使用Dictionary(grouping:by)方法,僅需一行代碼就可以達(dá)到上述效果找御。所要做的是傳入一個(gè)閉包元镀,該閉包返回?cái)?shù)組每一項(xiàng)項(xiàng)對應(yīng)的Key值即可。

// Swift 4.0
let groceriesByDepartment = Dictionary(grouping: groceries,
                                       by: { item in item.department })
// groceriesByDepartment[.bakery] == [??, ??]

最終的字典groceriesByDepartment對每個(gè)department都有唯一入口霎桅,而且該入口對應(yīng)著GroceryItem相應(yīng)的name栖疑。例如,使用.bakery作為入口滔驶,將返回[??, ??]數(shù)組遇革。

獲得字典值的數(shù)量

使用新的mapValues(_:)方法,用戶可以方便的獲得每個(gè)入口對應(yīng)數(shù)組的長度揭糕。以上面例子中獲取的groceriesByDepartment字典為例:

let departmentCounts = groceriesByDepartment.mapValues { items in items.count }
// departmentCounts[.bakery] == 2

因?yàn)樽值溆邢嗤膋ey萝快,只是值不同,所以可以不需要重新計(jì)算哈希值著角,從而使得調(diào)用mapValues(_:)方法比從頭建立字典快很多揪漩。

從鍵值對建立字典

Swift4提供了兩種方法給用戶從鍵值對序列生成字典,一種方法允許key有重復(fù)吏口,另一種不允許奄容。

使用zip(::)函數(shù)可以將一些了鍵值組合起來。例如下面的代碼就創(chuàng)立了一系列(String,GroceryItem)元組锨侯。

let zippedNames = zip(groceries.map { $0.name }, groceries)

zippedNames的每一項(xiàng)都是一個(gè)元組(tuple)嫩海,第一項(xiàng)是("Apples", ??).因?yàn)閚ame值是唯一的,下面的方法就可以創(chuàng)建一個(gè)字典囚痴,也是我們上面提到的不允許key值重復(fù)的方法叁怪。

<div align=center>



</div>

var groceriesByName = Dictionary(uniqueKeysWithValues: zippedNames)
// groceriesByName["Apples"] == ??
// groceriesByName["Kumquats"] == nil

當(dāng)然,要使用該方法的前提是你可以確保key值是不重復(fù)的深滚。否則會(huì)引起runtime error奕谭。

如果key值可能會(huì)重復(fù)涣觉,使用另一個(gè)方法:Dictionary(_:uniquingKeysWith:)。這個(gè)方法需要傳入一個(gè)閉包來處理當(dāng)key重復(fù)時(shí)的操作血柳。閉包的第一個(gè)參數(shù)是key(鍵)對應(yīng)的old value(值)官册,而第二個(gè)對應(yīng)的是新值。用戶可以在閉包里寫相應(yīng)的邏輯难捌,比如新值替代老值膝宁,或者將新老值合并。

let pairs = [("dog", "??"), ("cat", "??"), ("dog", "??"), ("bunny", "??")]
let petmoji = Dictionary(pairs,
                         uniquingKeysWith: { (old, new) in new })
// petmoji["cat"] == "??"
// petmoji["dog"] == "??"

看上面的例子根吁,dog對應(yīng)了兩個(gè)值员淫。當(dāng)方法處理到("dog", "??”)時(shí),閉包的參數(shù)是 ("??”击敌, "??”)介返,而閉包的邏輯是返回第二個(gè)值,因此新值就代替了老值沃斤,最終的字典中圣蝎,dog對應(yīng)的值就是??。

篩選出特定的項(xiàng)

字典現(xiàn)在有了一個(gè)filter(_:)方法衡瓶,返回值是滿足條件的新字典(早期版本的swift返回的是一個(gè)數(shù)組)徘公。方法傳入的參數(shù)依然是一個(gè)閉包,如果某一項(xiàng)需要在返回值中出現(xiàn)鞍陨,閉包返回true步淹,否則返回false。

func isOutOfStock(_ item: GroceryItem) -> Bool {
    // Looks up `item` in inventory
}

let outOfStock = groceriesByName.filter { (_, item) in isOutOfStock(item) }
// outOfStock["Croissants"] == ??
// outOfStock["Apples"] == nil

上例中诚撵,isOutOfStock決定某一項(xiàng)該不該出現(xiàn)在返回值字典中。

使用默認(rèn)值

字典現(xiàn)在提供了類似數(shù)組下標(biāo)來獲取和更新值键闺,下面的代碼定義了一個(gè)簡單的購物籃寿烟,key是商品,value是商品的數(shù)量辛燥。

// Begin with a single banana
var cart = [??: 1]

因?yàn)槟承﹌ey在字典中沒有對應(yīng)的值筛武,因此你用key去獲取值的時(shí)候,返回結(jié)果是optional的挎塌。

// One banana:
cart[??]    // Optional(1)
// But no shrimp:
cart[??]    // nil

可以使用??操作符將optinal值拆包為真實(shí)的數(shù)值徘六,現(xiàn)在swift4提供了另一種解決方案(設(shè)置默認(rèn)值),如果key對應(yīng)的值存在榴都,那么返回該值待锈,否則返回默認(rèn)值。如果key沒有對應(yīng)值嘴高,那么返回默認(rèn)值竿音。

// Still one banana:
cart[??, default: 0]    // 1
// And zero shrimp:
cart[??, default: 0]    // 0

甚至用下面的代碼簡化增加新item到購物車的過程和屎。

for item in [??, ??, ??] {
    cart[item, default: 0] += 1
}

當(dāng)循環(huán)處理到??時(shí),檢索到當(dāng)前值春瞬,然后自增柴信,放回到原字典中。當(dāng)檢索到??時(shí)宽气,發(fā)現(xiàn)??現(xiàn)在并沒有對應(yīng)值随常,從而返回默認(rèn)值0,自增為1萄涯,存儲(chǔ)到字典中线罕,下次檢索的時(shí)候就變成了1.

合并兩個(gè)字典到一個(gè)字典中

將兩個(gè)字典合并也變得異常簡單。swift4提供了merge(_:uniquingKeysWith:)方法來處理合并操作窃判。和上面一樣钞楼,需要傳入一個(gè)閉包完成合并的邏輯,當(dāng)兩個(gè)字典擁有相同的key值時(shí)袄琳,由該閉包處理如何操作询件。

let otherCart = [??: 2, ??: 3]
cart.merge(otherCart, uniquingKeysWith: +)
// cart == [??: 5, ??: 3, ??: 1]

上面的代碼將相同key對應(yīng)的值相加作為新字典中的值。

如果不想原地合并唆樊,可以使用merging(_:uniquingKeysWith:)方法生成一個(gè)新字典宛琅。

And That’s Not All…

上面介紹的新特性并不是全部,限于篇幅逗旁,并沒有完全介紹全嘿辟。

和字典一樣,集合也擁有了新的filter(:) 方法片效,返回的也是集合红伦,而不是早起版本中的數(shù)組。字典和集合現(xiàn)在提供了暴漏現(xiàn)在capacity的方法:reserveCapacity(:)淀衣,有了該方法昙读,用戶可以看到并控制他們的內(nèi)部存儲(chǔ)。

Reference

本文譯自:https://swift.org/blog/dictionary-and-set-improvements/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末膨桥,一起剝皮案震驚了整個(gè)濱河市蛮浑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌只嚣,老刑警劉巖沮稚,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異册舞,居然都是意外死亡蕴掏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來囚似,“玉大人剩拢,你說我怎么就攤上這事∪幕剑” “怎么了徐伐?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長募狂。 經(jīng)常有香客問我办素,道長,這世上最難降的妖魔是什么祸穷? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任性穿,我火速辦了婚禮,結(jié)果婚禮上雷滚,老公的妹妹穿的比我還像新娘需曾。我一直安慰自己,他們只是感情好祈远,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布呆万。 她就那樣靜靜地躺著,像睡著了一般车份。 火紅的嫁衣襯著肌膚如雪谋减。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天扫沼,我揣著相機(jī)與錄音出爹,去河邊找鬼。 笑死缎除,一個(gè)胖子當(dāng)著我的面吹牛严就,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播伴找,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼盈蛮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了技矮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤殊轴,失蹤者是張志新(化名)和其女友劉穎衰倦,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旁理,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡樊零,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驻襟。...
    茶點(diǎn)故事閱讀 38,683評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡夺艰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沉衣,到底是詐尸還是另有隱情郁副,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布豌习,位于F島的核電站存谎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏肥隆。R本人自食惡果不足惜既荚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望栋艳。 院中可真熱鬧恰聘,春花似錦、人聲如沸吸占。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旬昭。三九已至篙螟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間问拘,已是汗流浹背遍略。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留骤坐,地道東北人绪杏。 一個(gè)月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像纽绍,于是被迫代替她去往敵國和親蕾久。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理拌夏,服務(wù)發(fā)現(xiàn)僧著,斷路器,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • #閉包(Closures) 本頁包含內(nèi)容: - 閉包表達(dá)式(Closure Expressions) - 尾隨閉包...
    刺骨寒閱讀 1,248評論 0 0
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 3,784評論 1 10
  • 86.復(fù)合 Cases 共享相同代碼塊的多個(gè)switch 分支 分支可以合并, 寫在分支后用逗號(hào)分開障簿。如果任何模式...
    無灃閱讀 1,354評論 1 5
  • 文|京芮兒 洛菲克研究室盹愚,一項(xiàng)秘密計(jì)劃正在有條不紊進(jìn)行著。 兩個(gè)頭戴灰色鴨舌帽站故、身穿灰色制服皆怕,嘴上戴著藍(lán)色醫(yī)用口罩...
    京芮兒閱讀 925評論 2 7