ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Swift AlgorithmsパッケージとSwift Collectionsパッケージについて
Appleが提供するオープンソースのSwiftパッケージリストに追加された最新アイテムの2つであるSwift AlgorithmsとSwift Collectionsを紹介します。これらのパッケージをそのまま使用できるだけでなく、Swift Standard Libraryに最終的に含まれる新しいアルゴリズムとデータ構造がこれらのパッケージから創出されます。これらのパッケージをプロジェクトに統合して、適切なアルゴリズムとデータ構造を選択して、コードを明瞭化および高速化する方法を紹介します。
リソース
関連ビデオ
WWDC22
WWDC21
WWDC20
-
ダウンロード
♪ (Swift Algorithmsパッケージと Swift Collectionsパッケージについて)
こんにちは 私はKyleです Swift Standard Libraryチームは Swift ArgumentParser Swift Numerics及び Swift Systemを含む オープンソースパッケージの 成長中の項目を維持します 本日 私たちは 二つの ファミリーに追加する新製品を ご紹介することに ワクワクしています: Swift Algorithms及び Swift Collectionsです! Swift Algorithmsは Swift Standard Libraryを 増加させるシーケンスおよび コレクションアルゴリズムの オープンソースパッケージです Swiftの最も強力な 機能の一つは 内蔵されている アルゴリズムの豊富な 分類項目です 用語を学ぶために少し 投資が必要ですが 学習後容易に目に見えるような いくつものアルゴリズムが 隠れていて それらを採用することにより あなたのコードの質をどれだけ 改善できるかを発見するという 印象的なものとなります 私が意味することを理解するため 私が作業を行っている メッセージアプリケーションから いくつかコードを見てみましょう 送信または削除のために対応する メッセージをすべて収集する テーブルビューの選択された列ごとの インデックスパスを何度も通る このループをお考えください これはただのマップです マップを使用してこのコードを読む ためにもっとはっきりさせます なぜならそれは 長さや 複雑さに関わらず 締結する本文の 追加の脈絡を提供して 入力を変化させているからです このマップを使用すると このコード をより高速にします なぜならそれは列のループが それを 行わなかったものである 予備の容量により配列の サイズを変更するため 中間の配置を避けるからです またはユーザーが画像を タップする場合はこのループが チャット内容で メッセージを繰り返し Quick Lookを使用して表示する ためにすべての添付を中止します これはただのマップと フィルタです! 実際このフィルタ ニルの パターンとオプションを開くための マッピングは 非常に一般的なため 当社には そのための特殊な名称と アルゴリズムがあります compactMap 次にこのコードをお考えください 私には メッセージの配列が あり チャット内容の 項目の配列にそれを 変形したいと思います 巧妙なことはいずれの 与えられたメッセージは チャット内容の複数の項目に 対応することができることです このマップを使用して 例の配列を作成します しかしそれは私が行いたいことでは なくフラットな配列が必要です ループごとの列をまた使用しければ ならないという意味でしょうか? もちろん違います 他のアルゴリズムがあります それは「joined」と呼ばれます それが行うことは全ての内側の 配列を全て一緒に 単一要素のフラットコレクションに 加えることです このマッピングパターン及び 結合は非常に一般的なため そのためのもう一つの特別な マップを定義します:flatMap もちろんマップとフィルタは 氷山の一角です 私のAppのチャット詳細画面の 列のループをお考えください 私は チャット内の最後の6枚の 写真を最新のものから 一番古いものまで 表示したいと思います チャット内容を 逆の順序で 繰り返します 最新から一番古いものへ そして 項目が写真である場合 それを配列に追加します そして6枚になったら停止します スタンダードライブラリからの アルゴリズムを 一緒に変更することにより これをさらに簡潔に表現できます 最初の6枚を超えないように するため 逆の compactMap そして prefix アルゴリズムを一緒に変更する ことはこのコードを さらに明確に表現するために さらに柔軟性をもたらします 例えば私は逆向きのチャット 内容のprefixよりも チャット内容のsuffixに関する このオペレーションについて 考えるほうがもっと 自然だと思います そのためアルゴリズムの チェーン は 列のループよりも さらに明白で簡潔ですが パフォーマンス は どう比較するのでしょうか? チェーン内の各手順が 中間配列を配置する場合 別のループよりも 遅くならないでしょうか? 答えは YES です スタンダードライブラリが 一部の 賢い秘訣を 実行していなければ 私たちが先ほど見た結合 アルゴリズムに戻って 何が起こっているかを 詳しく見てみましょう 結果として結合は 実際には 配置せず 新規の配列を返します 代わりにそれは FlattenSequenceを返します FlattenSequenceは私たちが "lazy adapter"と呼ぶものです ほとんどの目的でそれは 配列のように機能しますが それはただの薄いラッパーなので 効果的に自由に作成します それはなまけものなので 全ての作業を前もって行わずに 必要に応じて 要素を処理します FlattenSequenceなどの レイジーアダプタが アルゴリズムチェーンが ループの列で競争力のある パフォーマンスを行えるように するためのものです 詳細画面に戻って 詳しく見て チャット内の最後の6枚の写真を 処理するアルゴリズムを 見ましょう 接頭辞が実際配列スライスを 返すのが分かります 賢いです そして 逆のもレイジ アダプタとして実行され 終わりで開始し 開始で終わるよう 仲介します compactMapは どうでしょうか? 依然配列を返します 怠けることがあるでしょうか? あります チェーンの始めにを 追加するだけで マップとフィルタの ように締結する アルゴリズムを作ります 怠け者です! レイジーアルゴリズムチェーンは このような ユースケースに非常に よく適合します 潜在的に非常に大きな コレクションから 少数の要素のみを 処理する場合は もちろん 時々する必要がある または配列が必要です その場合は常にアルゴリズム チェーンを 配列イニシャライザで ラッピングできます これはもうひとつのスタンダード ライブラリチームの利点です 私たちはレイジ アルゴリズムの大ファンです レイジーアルゴリズムを熱望する 結果に変えるのは本当に簡単ですが 逆 へ行くのは不可能です なので私はメッセージ Appで 大きく進歩し 私のデザイナーは機能の リクエストのために 近づきます 彼らは 二つの連続する メッセージの間で 1時間以上が経過した場合 チャット内容に タイムスタンプを含める ことを望んでいます 合理的に見えます このために使用できる もうひとつのアルゴリズムが なければならないですよね? あります ただしそれにアクセスするには Swift Algorithms パッケージを インポートする必要があります しばらくの間に一度 皆さんは Swift スタンダード ライブラリが それに対応 しないというような ユースケースに遭遇します このアルゴリズムパッケージの 目的は摩擦の少ない場所を もたらすことです皆さんのお手伝いにより スタンダードライブラリ内の 最終的な内容物の欠けている アルゴリズムの新しい ファミリーを温めます 当社は40以上のアルゴリズムを Swift Algorithmsに追加しました 述語により決定される 2つか3つかグループによる またはコレクション内の 5つの最も小さい要素の選択 5つの最も大きいまたは ランダムで5つによる全ての コンビネーションの生成 または集合要素の置き換えまたは 順序の要素の重複などのため Swift Algorithmsに伴う 強力な 反復ツールの 一部を詳しく見てみましょう windows(ofCount:)は スライド式のウインドウを提供し こちらはサイズ3で要素の 集合に向かいます ループの各回でウィンドウは 基本的コレクションの 連続に過ぎません こちらのArraySlice は 中間の配置を回避します windows(ofCount: 2)は 特に一般的で 便利なものがあります それは"adjacentPairs" と呼ばれます adjacentPairsは連続ではなく 組を提供し さらに多くの 便利な要素へのアクセスを 可能にします もう一つの強力な反復ツールは chunks(ofCount:)です Windows と異なり チャンクは重複しません コレクションがチャンクカウント により均等に分けられない場合は シーケンスの最後のチャンクは 余りを含みます そして Windows のように チャンクはベースコレクションの 連続なので安価で作成できます 時々コレクションを 要素のような 物に チャンクして 実行させたいでしょう ここでは isPrimeで チャンクしています これはisPrime に対応する 同じ値を返す連続する要素の チャンクを反復する という意味です 都合を良くするため chunked(on:)は チャンクとチャンクされる値の 両方の組を提供します 今までに前回と現在の 要素が異なる場合 一部の作業のみを行う このような別のループを 書いている自分に 気づいたことはありますか? これはひとまとめになっています! 私のデザイナーがチャット内容に メッセージの間で 1時間が経過した時は タイムスタンプを含める 機能のリクエストに 戻りましょう 思い出してみると 私たちはチャット内容の 項目を作るためのメッセージを わたるフラットマッピングにより チャット内容を作成します 全てのチャット内容の項目は その日付にアクセスできます 私たちは その間で1時間 以内が経過した場合 その 日付でグループ チャット内容の 項目に一つにまとめます 私たちはすでにチャンクが コレクションを要素のような 実行にまとめるかを 見ています Swift Algorithms はカスタム 述語を提供できるようにする チャンクされた別の形に なっています それは要素の隣接するペアを渡し 同じグループに属する場合は を返します ここでは チャット内容の 項目の間が 1時間以内の場合 を返します 次に タイムスタンプを作成して 全てを単一の フラットコレクションに 追加する必要があります 先ほど私達はフラットされた ものに入れ子式にされた コレクションを組み合わせました スタンダードライブラリーは 区切りを挿入することができる 他の結合の異型物です このアルゴリズムを使用して 改行またはカンマの区切りなどの 文字列を 一緒に合わせることは 本当に一般的です でも このばあいは 定数区切り文字 十分ではない。 私たちは次のチャンクに 最初の日付にアクセスしなきゃ タイムスタンプを構築するから アルゴリズムパッケージは 別のjoinedの変形を含みます その変形が前後のチャンクから 区切り文字を計算します ここでそれを使って一緒に戻って 結合するにはことができます タイムスタンプで区切られている トランスクリプトアイテムのチャンクを かなり満足ですね? もちろん、私たちは支払うことが必要ありません これらのいずれかの中間配分のために これすべては請求によって ただ .lazyを追加して計算できます 行こう! 怠惰は魔法の解決策ではないと注意したい あなたが一度だけシーケンスを反復するとき 請求によって計算したら 配分も仕事もへらす しかしあなたがシーケンスを 何度も何度も反復しているとき メッセージングAppで私は トランスクリプトを使ってするように 請求によって計算するのは 同じ仕事がなんでもなんでも繰り返す マッピング チャンク および結合 ユーザーが毎回 編集モードに入ると 画像をタップする または詳細画面を訪問します。 この場合は あなたは怠惰なアルゴリズムチェーンを まだ使用する必要があります。 それは最後のステップとしてちょうど あなたの仕事を言いますは もっと効率的になります すべてを配列に収集することにしったら 私たちはダース以上の 異なるアルゴリズムを見てきました Swift標準ライブラリや アルゴリズムパッケージから それらのすべてが動作します 配列だけでなく しかし 文字列も そして他のすべてのSwiftタイプ それはシーケンスやコレクションの 議定書に準拠しています すべてのデータ構造を 新しいSwift Collections パッケージに含む アルゴリズムを連鎖させたら コードをより明確にする より速くより正確にする そしてそれに熟達するようになるのは 複雑ではありません それはちょうどあなたの 語彙を構築するだけです ですから ローループを次回書くとき それがマップ フィルタ または他のアルゴリズムのいずれかの 立ち止まって考えてみてください 何も気にしないなら ドキュメントを検索するか またはSwift Algorithms GitHub レポジトリのガイドを読んでください またはSwiftフォーラムで 私たちを訪問してください フォーラムで一緒に 理解することができます 誰かにそれは役立つかもしれないですし Algorithmsパッケージへの新規追加に インスピレーションになるかも 次はKaroyがお教えします 新しいSwift Collections パッケージに付属する 汎用性のデータ構造について Karoy? ありがとうLyle! データ構造の話をしてみましょう Swift標準ライブラリは 3つの主要な汎用データ構造の ものだけを実装しています 配列 順序付けられていないセットと 辞書 を提供します これらは普遍的なコレクションタイプとして 偉大な選択肢を証明しています そして モジュールの境界を越えて データ転送に向いています これらはコピーオンライト バリューセマンティクスを実装する 効率的なインプレース ミューテーション操作を提供 コレクション値を周りを通過しても 作成されたコピーに 予想外の変化する突然変異 がないような安全性確認します しかしデータ構造はさらに 多くのものがあります 選ぶべきより大きい選択を 持っていると便利でしょう 今年の初めに私たちは 新しいデータ構造の実装である Swift Collectionsパッケージを リリースしました このパッケージはSwift開発者が Swift標準ライブラリに含める前に 新しいコレクションタイプを 試してみることができます Swift Collectionsパッケージを インポートすることで 追加の型にアクセスできます パッケージの初期バージョンでは 最も頻繁に要求される3つのデータ構造が 実装されています これらは3つの標準的な コレクションタイプの 新しいバリエーションです ダブルエンドのキュー OrderedSetと OrderedDictionaryを持っています これらは 配列 セット および辞書に似ています 彼らは同じテーマの変種で 既存の構造体に 新しい機能を追加します これらの新しいタイプは 既存のタイプの 代替品ではなく それらを補完しています。 いくつかのユースケースでは 新しい型はより良くフィットします ただし 他の多くの場合 既存のタイプは 引き続き正しい選択です どのデータ構造にリーチするかを 知るためには これらが既存の型とどのように 異なるかを学ぶ必要があります それではこれらを 簡単に見てみましょう ダブルエンドのキューから始めます または むしろ 一般的にキュ スーパーで並んで待っている顧客から アプリケーションの非同期タスクまで 任意の数のアイテムを 一つずつ処理する必要がある場所に キューがポップアップ表示されます ほとんどの抽象形式において キューは2つの主要な 操作を提供します キューの最後にアイテムを プッシュでき 最初から要素を取り出します
両端キューはこうしたキューの 操作を対称にします これは新しいアイテムを キューの最初に効果的に プッシュすることを サポートします 最後から要素を 取り出すことも
「両端キュー」という名前は 便利なタイプに 最適な名前です そのため短くして「デック」 と言います 音節をもう一つ 削るために これは伝統的に 「デック」と発音します トランプ一組のように コレクションパッケージでは デックにはなじみがある配列タイプ とほぼ同じAPIがあり 多くの同じプロトコルを 実行します 例えばキューを作るために 配列リテラルを使います デックにはRandomAccessCollection プロトコルに従います 配列のようにデックは コレクションの最初から測定した オフセットである整数インデックス を使用します これによりポジションを基に 要素に簡単にアクセスできます 例えば このデックのインデックス1の 要素は文字Eです このコレクションの最後の 小文字fが気になるのは 私だけではありません 幸運にもデックは MutableCollection プロトコルに従いインデックス2 から割り当てて修正します 小文字のfを大文字のF に交換します 良く見えますね! デックは RangeReplaceableCollection プロトコルを実行するので 要素のサブレンジの 挿入 削除や交換に 馴染みがある操作すべてを 提供します 例えばゼロのインデックスで insert(contentsOf:) メソッドを 呼び出してデックの 最初に シーケンスを挿入します この実行方法は配列とは異なる デックから始まります 項目を保存する配列を 使用した場合 最初に新しい要素を 挿入することは 新しいものに場所を あけるために 既存の要素を移動して 開始する必要があります 可能な限りシンプルに アクセスするために 配列は1つの連続バッファで 要素を維持し ストレージのデックから 始まります 配列が大きすぎると 比較的効果な新しい要素を 先頭に追加します 最初に新しい要素を 挿入することは時間がかかり 要素の数にほぼ比例し 既に配列にあります デックの異なって 機能します 境界周辺のストレージ バッファをラップするので 新しい要素を既存のもの 動かさずに先頭に 追加します インデックスはコレクションの 最初の論理から 提供されます そのため挿入 インデックス1の 要素は列Bです これはデックが論理的 インデックスと 実際のストレージポジション の間で翻訳するために 取り組む必要がある ということです しかし要素へのアクセスは とても異なるものです デックの先頭に 追加することは 既存の数字のスライドを 解決しません 配置より劇的に速く これを操作することができます 最初に新しい要素を挿入 するには 一定の時間がかかります 要素がコレクションに どれだけあってもです これがデータ構造の 力です ツールボックスに それがあると 以前は及ばなかった 問題を解決するために それを使用できます 右のデータ構造に 変えると すべてを変更できます 使用することが楽しい responsive wonderへと 使用できない遅いAppを 変えることができます もちろんデックも ストレージの中心で どのように操作するのか とてもクレバーなります 例えば要素の範囲を 削除するとき デックはその後のもの ではなくそれ以前の要素を 移動させて結果のギャップを 埋めるオプションがあり これは移動させる必要がある 要素の数を減らせます これは要素を前に付けることほど 劇的な改善ではありません しかしランダムに要素を 削除するとき 平均より2倍速く ものを作ります これがデックです 順序集合を見てみましょう 標準で既存のセットタイプは コレクションで すべての要素がユニークで あることを保証します しかし最初の順序付けを 保存しません 実際にセットの要素の順序は 効果的にランダムです これは2つの同じセットの インスタンスが 2つの完全に異なる配列で 一覧にします これにも関わらず同じ要素を 含む2つのセットは 同等とみなされます 順序は重要ではありません ユニークさを保証したいとき これは最高のものですが 要素がどう順序付けられるのか 管理したいときがあります 例えばやることリストの Appを書いています アイテムを一度だけリストに することを保証したいのですが ユーザーが設定した 特定の順序を維持したいのです これが順序集合が行う ことです ビューポイント次第で 要素をユニークのままにする 配列のようなものか メンバーに構築した順序を 保存する セットとして見ることができます 配列やセットのように 順序集合は配列リテラルで 明確です しかしセットとは異なり 要素の順序は保存が 保証されています 順序は重要です 同じメンバーを含まない場合 2つの順序集合が 同等のものを比較しますが 同じ順序である必要があります 2つの順序集合があらゆる順序で 同じ要素を含んでいるのか ただ知る必要がある場合 特別の順序付けられていない ビューで比較できます この軽量のビューは要素の 順序を無視するので より従来型のセットのような インターフェースを 提供します しかしデフォルトで順序集合は 配列がどう機能するかに似ています これは順序集合が整数オフセット インデックスを伴う ランダムアクセスコレクション であることにより強化されます 配列やデックのように アイテムにアクセスするために 整数添字を使用できます セットから予測できるように 要素を追加して削除できます しかしこうした操作はポジションを 考慮する必要はあります 例えば追加の操作があり メンバーではない場合には セットの終わりに新しい 要素を追加します 戻り値は要素が追加される 必要があるかどうか示し アイテムのインデックスも 報告します 特定の場所に新しい要素を置く 挿入操作もあります この場合文字Bは 既にあるので 操作はただ既存のメンバーの インデックス 戻すだけです エレメントの削除は順序集合に 穴を残し メンバーの残りは埋めるために 移動する必要があります 配列のように 順序集合は要素をユニークに しておく必要があるため 任意のアイテムの交換を サポートできません これは配列とは異なり MutableCollectionや RangeReplaceableCollection プロトコルに確認できません しかし並び替えやシャッフル のような 標準的な記録操作を サポートします 順序集合は順序を保存する方法で SetAlgebraから すべてのレベルのセットの 操作を実行します 例えば共用体の形成は 欠落している要素を 2番目のセットに現れる順番に 付け加えます セットを差し引くことは 最初の順序で 残りの要素を維持します 順序はほとんどの SetAlgebraの操作を 実行しますが プログラムを正式に 確認できません 要素の順序が重要ではない ということを 必要とするからです しかし順序づけられていない ビューには 順序に依存しない平等の コンセプトがあります SetAlgebraに従います SetAlgebra値を 必要とする機能に OrderedSet 値を パスするために使用できます フード 標準の下を見て 順序づけられていない セットタイプは ランダムにシードされた ユニバーサルハッシュ関数を使い フラッシュハットテーブルに 直接要素を保存します これは要素のパフォーマンスに 最高の検索を提供しますが 最初の順序を無視します 任意性 ユーザー指定の要素の 順序をサポートするために 順序集合は通常の配列の インスタンスを代わりに 要素を保存します 順序集合はまだ同じ 拘束で安全な ハッシュテーブルの実装を 使用していますが この場合 テーブルはストレージ配列に 整数インデックスを保存する 必要のみがあります こうした整数の範囲は ハッシュテーブルのサイズに 制約されるので できるだけ少ないバイトに 整数値を圧縮してテーブルを 圧縮できます これは通常のセットと比較し かなりの量のメモリを保存でき ほとんどの操作のために 競争力のあるパフォーマンスを 維持しています 検索のパフォーマンスは 標準セットに匹敵します ランダムメンバーを見つけるには コレクションのサイズに関わらず 一定の時間がかかります 配列は各要素を入念に見る 必要があり コレクションが増加するため 時間がかかります 順序集合に新しい要素を 加えることは 標準セットに要素を 挿入することと 同等のことを行います これはまだ新しアイテムを ハッシュ化する必要があり 要素が既に存在する場合は 確認を含むので これはシンプルな配列に 要素を直接追加する以上に 複雑な操作です しかしどれほどコレクションが 大きくなっても それでも一定の 時間がかかります OrderedSetは既存の要素を すぐに検索でき 新しい要素を追加できますが 効果的にセットの最初または中央で アイテムを削除または挿入を 効果的に実行できません 配列のようにこうした操作は ストレージ配列で 要素をスライドする必要が ありますが ハッシュテーブルに後続の インデックスの番号を 付け直す必要があります これは削除と挿入は 線形複雑度により 操作となることを意味し 通常セットより遅くします これは常にトレードオフです! しかしこうしたデータ構造が どう機能するかよく理解すると 最適化するために重要な操作と 満たす必要がある要件に基づき 問題を解決するために自信を持って 正確なものを選択できます 正確なデータ構造の選択は 数百または数千倍速いコードとなる アルゴリズムの改善に 繋がります 間違ったものを選択すると 逆になります 究極的には最高のAppとなり ユーザーを満足させるため こうしたことを学ぶことは 便利だと思います この新しいOrderedSet タイプはFoundationの 純粋なSwiftの変数です しかしOrderedSetは パッケージで実行されるため NSOrderedSetへの 架け橋とはなりません これは既存の Objective-CのAPIは 新しいタイプを使用するために 自動的にインポートされません これらは別のことです
コレクションパッケージ により提供される 第3のデータコレクションは 標準の辞書型の順序付けられた アナログです 標準の辞書のように これはキーと値のペアの 順序であり これにより添字として キーを利用でき 対応する値を素早く 検索します 通常の辞書とは異なり キーと値のペアの順序は 明確に定義されています デフォルトでキーが最初に 挿入された 順序に従います 新しい要素を追加するために 新しいキーに値を代入します 既存のキーにNIL代入して 要素を削除できます こうした操作を通して 順序付けられた辞書は 明確に定義された順序で コンテンツを維持します
順序で付けられた辞書は 配列のような整数インデックスを 仕様しますがこれは興味深い 問題を導入します 例の辞書では インデックス添字演算子は キー添字と対リスします ゼロで添字を付ける場合 主要なゼロの値へのアクセスを 意味するのか それともゲンテンオフセットで キー値ペアの検索を意味しますか?
キーベースの添字は 辞書型の主な操作なので 曖昧さを回避するために 順序付けられた辞書の添字は常に キーイングの添字を意味します OrderedDictionaryは インデックス添字演算子を 提供しません OrderedDictionaryは コレクションにはならないことを 意味します コレクションプロトコルは 添字などを必要とするからです そのため OrderedDictionaryは シーケンス型プロトコルのみに 従います しかしコレクションの適合性が 望ましい場合 OrderedDictionary は特別な 要素ビューを提供します 要素はランダムアクセス コレクションであり キー値ペアを戻す インデックス添字を提供します 基本的な実装を見て 通常の辞書型はキーと値を それぞれ保存するために 2つの別々のハッシュテーブルを 使用しますが 順序付けられた辞書は1つの 圧縮されたハッシュテーブルと 2つの並行配列を代わりに 仕様します これは順序集合より多くの スペースを保存できます コレクションパッケージでは 3つの利用できる 新しいデータ構造があります このような構造を使用して Appのパフォーマンスを 高めることができ またはメモリの使用を削減したり 重要なことは 誓約を表現できることであり セットの要素の順序を保存する ような標準型で簡単に 満たすことはできません こうした新しいタイプはすべて シーケンスプロトコルと コレクションプロトコルに従って いるため 標準ライブラリに提供される アルゴリズムと カイルがお見せした アルゴリズムパッケージを 結合します Swift コレクションと Swift アルゴリズムは オープンソースパッケージの 増加するリストの新しい メンバーの2つにすぎません 現在新しいプラットフォームと 新しいドメインにプッシュ しているため Swiftライブラリエコシステムの 将来は現在形成されています ますますオープンソース パッケージを活用しているため よく見える状態で 行われています 故意にこうしたパッケージを 早くにリリースし 一方これらはまだ柔軟であり GitHubへのコミュニティの 取り組みとして開発しています 試してみてください 問題を送付してください プルリクエストを開いてください 関わり合い影響を与えるために 今より良い時 簡単なときはありません 私たちのように皆さんが 新しいSwiftパッケージに ワクワクしていることを 期待しています これで構築するものを 早く見たくてたまりません ご視聴ありがとうございました WWDCの残りを楽しんでくださいs! ♪
-
-
1:00 - The map algorithm
// Raw loop: var selectedMessages: [Message] = [] for indexPath in indexPathsForSelectedRows { selectedMessages.append(messages[indexPath.row]) } // Using `map` makes this clearer and faster. indexPathsForSelectedRows.map { messages[$0.row] }
-
1:36 - The compactMap algorithm
// Raw loop: var attachments: [Attachment] = [] for message in messages { if let attachment = message.attachment { attachments.append(attachment) } } // The above is just a `map` and a `filter`. messages .filter { $0.attachment != nil } .map { $0.attachment! } // This pattern is so common we have a special name and algorithm for it. messages.compactMap { $0.attachment }
-
2:06 - The flatMap algorithm
extension Message { func makeMessageParts() -> [TranscriptItem] } messages // [Message] .map { $0.makeMessageParts() } // [[TranscriptItem]] .joined() // [TranscriptItem] // This pattern is so common that we have another special kind of map for it. messages // [Message] .flatMap { $0.makeMessageParts() } // [TranscriptItem]
-
3:00 - Chaining together algorithms
// Raw loop: var photos: [PhotoItem] = [] for item in transcript.reversed() { if let photo = item as? PhotoItem { photos.append(photo) if photos.count == 6 { break } } } // The above can be expressed more concisely by chaining together algorithms. transcript .reversed() // [TranscriptItem] .compactMap { $0 as? PhotoItem } // [PhotoItem] .prefix(6) // [PhotoItem] // This gives us more flexibility to express this code more clearly. transcript .compactMap { $0 as? PhotoItem } // [PhotoItem] .suffix(6) // [PhotoItem] .reversed() // [PhotoItem]
-
4:19 - Lazy adapters
extension Message { func makeMessageParts() -> [TranscriptItem] } messages .map { $0.makeMessageParts() } // [[TranscriptItem]] .joined() // FlattenSequence<[[TranscriptItem]]>
-
4:58 - Lazy algorithm chains
transcript .lazy // LazySequence<[TranscriptItem]> .compactMap { $0 as? PhotoItem } // LazyCompactMap<[TranscriptItem], PhotoItem> .suffix(6) // LazyCompactMap<ArraySlice<TranscriptItem>, PhotoItem> .reversed() // ReversedCollection<LazyCompactMap<ArraySlice<TranscriptItem>, PhotoItem>>
-
5:48 - Wrapping a lazy algorithm chain in an Array initializer
Array( transcript .lazy .compactMap { $0 as? PhotoItem } .suffix(6) .reversed() )
-
7:13 - windows(ofCount:)
import Algorithms let x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] for window in x.windows(ofCount: 3) { print(window) } // Prints [0, 1, 2] // Prints [1, 2, 3] // Prints [2, 3, 4] // Prints [3, 4, 5]
-
7:30 - adjacentPairs()
import Algorithms let x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] for (prev, next) in x.adjacentPairs() { print((prev, next)) } // Prints (0, 1) // Prints (1, 2) // Prints (2, 3) // Prints (3, 4)
-
7:45 - chunks(ofCount:)
import Algorithms let x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] for chunk in x.chunks(ofCount: 3) { print(chunk) } // Prints [0, 1, 2] // Prints [3, 4, 5] // Prints [6, 7, 8] // Prints [9]
-
8:08 - chunked(on:)
import Algorithms let x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] for (isPrime, chunk) in x.chunked(on: \.isPrime) { print((isPrime, chunk)) } // Prints (false, [0, 1]) // Prints (true, [2, 3]) // Prints (false, [4]) // Prints (true, [5])
-
8:33 - Recognizing the chunked(on:) pattern
// Raw loop: var prev: Element? for element in collection { if prev?.value != element.value { // do work } prev = element } // The above is just `chunked(on:)`. for (value, chunk) in collection.chunked(on: \.value) { // do work }
-
8:49 - Mapping, chunking, and joining
import Algorithms extension Message { func makeMessageParts() -> [TranscriptItem] } transcript = Array( messages .lazy .flatMap { $0.makeMessageParts() } .chunked { $1.date.timeIntervalSince($0.date) < 60 * 60 } .joined { DateItem(date: $1.first!.date) } )
-
14:56 - Double-ended queues
var queue: Deque = ["A", "B", "C"] queue.append("D") queue.append("E") queue.removeFirst() // "A" queue.removeFirst() // "B" queue.prepend("F") queue.prepend("G") queue.removeLast() // "E" queue.removeLast() // "D"
-
15:46 - Deque protocol conformances
var items: Deque = ["D", "E", "f"] print(items[1]) // "E" items[2] = "F" items.insert(contentsOf: ["A", "B", "C"], at: 0) print(items[1]) // "B"
-
17:31 - Accessing elements is still efficient
var items: Deque = ["D", "E", "F"] print(items[1]) // "E" items.insert(contentsOf: ["A", "B", "C"], at: 0) print(items[1]) // "B"
-
18:39 - Removing elements at random is twice as fast on average
var items: Deque = ["A", "B", "C", "D", "E", "F"] items.removeSubrange(1 ..< 3)
-
19:33 - Unordered sets
let first: Set = ["A", "B", "C", "D", "E", "F"] print(first) // ["B", "E", "C", "F", "D", "A"] let second: Set = ["A", "B", "C", "D", "E", "F"] print(second) // ["A", "D", "E", "F", "C", "B"] print(first == second) // true
-
20:26 - Ordered sets
let first: OrderedSet = ["A", "B", "C", "D", "E", "F"] print(first) // ["A", "B", "C", "D", "E", "F"] let second: OrderedSet = ["F", "E", "D", "C", "B", "A"] print(first == second) // false print(first.unordered == second.unordered) // true
-
21:04 - Ordered sets resemble how arrays work
var items: OrderedSet = ["E", "D", "C", "B", "A"] items[3] // "B" items.append("F") // (inserted: true, index: 5) items.insert("B", at: 1) // (inserted: false, index: 3) items.remove("E") items.sort() items.shuffle()
-
22:32 - Ordered sets implement high-level set operations
var items: OrderedSet = ["B", "D", "E"] items.formUnion(["A", "B", "C", "F"]) items.subtract(["A", "B", "G"]) let other: OrderedSet = ["C", "D", "E", "F"] print(items == other) // false print(items.unordered == other.unordered) // true
-
26:46 - Ordered dictionaries
var dict: OrderedDictionary = [2: "two", 1: "one", 0: "zero"] print(dict[1]) // Optional("one") print(dict) // [2: "two", 1: "one", 0: "zero"] dict[3] = "three" dict[1] = nil print(dict) // [2: "two", 0: "zero", 3: "three"]
-
27:38 - Subscripting always means the keying subscript
var dict: OrderedDictionary = [2: "two", 0: "zero", 3: "three"] print(dict[0]) // Optional("zero") print(dict.elements[0]) // (key: 2, value: "two")
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。