2016-12-30 8 views
0

Swift 3で辞書の配列を並べ替えるのに時間があります。Swift 3、辞書の配列を並べ替え

var dicArray = [Dictionary<String, String>()] 
let dic1 = ["last": "Smith", "first": "Robert"] 
dicArray.append(dic1) 
let dic2 = ["last": "Adams", "first": "Bill"] 
dicArray.append(dic2) 
let sortedArray = dicArray.sort { ($0["last"] as? String) < ($1["last"] as? String) } 

うまく行っておりませんスウィフト3に同じコードを変換する:

はスウィフト2では、私はそれをうまく働いたこの方法は、だろう。

let sortedArray = dicArray.sorted { ($0["last"]! as String) < ($1["last"]! as String) } 

しかし、アプリが常にオプション値をアンラップしながら、それがnilを見つけたというエラーで、クラッシュ:システムは、(遠回りのルートで)これに私を導きました。 ?!

、あまりにも長い間テーブルに対して私の頭を叩いてありとあらゆる組み合わせてSとSを入れた後、私は仕事を得るために、古いアプローチに頼っ:

作品
let sortedArray = (dicArray as NSArray).sortedArray(using: [NSSortDescriptor(key: "last", ascending: true)]) as! [[String:AnyObject]] 

、およびI私は一緒に動いていますが、それほど甘いのではありませんか?

どこが間違っていましたか?このような場合、純粋なSwiftソート機能を動作させるにはどうすればよいですか?

+2

静的なキーセットを使用している場合は、必ずdictではなくstructを使用してください。 – Alexander

+2

@Alexanderが書いているように、構造体を使用してください:キーが静的ではない場合、上記のソートは非常に脆弱ですw.r.t.辞書の配列内のすべての辞書に実際にキー「last」が含まれていることを確認する必要があります。 'dicArray.contains(where:{!$ 0.keys.contains(" last ")})'が 'true'ではないことをチェックします。このようなガードを最初に組み込んでいた場合は、入力確認に違反しているので、空の追加辞書をキャッチしたでしょう。 – dfri

答えて

5

どこが間違っていましたか?

は、それはあなたの最初の行に間違っていた:あなたが欲しいものをやったことがない

var dicArray = [Dictionary<String, String>()] 

こと、でもスウィフト2に、あなたが実際に配列に余分な、空の辞書を挿入しているため。それがクラッシュの原因です。空の辞書には"last"というキーがありません。これは空のためです。

var dicArray = [Dictionary<String, String>]() 

が違いを参照してください。

あなたはこれをしたいですか?その変更後は、すべての場所に落ち、:

var dicArray = [Dictionary<String, String>]() 
let dic1 = ["last": "Smith", "first": "Robert"] 
dicArray.append(dic1) 
let dic2 = ["last": "Adams", "first": "Bill"] 
dicArray.append(dic2) 
let sortedArray = dicArray.sorted {$0["last"]! < $1["last"]!} 
// [["first": "Bill", "last": "Adams"], ["first": "Robert", "last": "Smith"]] 
+0

私はそれを信じられません。良い目。本当にありがとう。 – Retro

0

むしろキーの固定セットに辞書を使用するよりも、それはあなた自身のカスタムタイプを作成するために、一般的にお勧めです。この方法で

struct Person { 
    let lastName: String 
    let firstName: String 
} 

、あなたが持っていることはありませんコンパイラがプロパティの名前のチェックを強制するため、辞書の右の特定の値のキーがあるかどうかを心配する必要があります。これにより、堅牢でエラーのないコードを書くのが容易になります。

そして、偶然にも、ソートクリーナーも作成します。

let people = [Person(lastName: "Smith", firstName: "Robert"), Person(lastName: "Adams", firstName: "Bill")] 
let sortedPeople = people.sorted() 

:あなただけの素敵な Personタイプ内にカプセル化比較ロジックを保ち、それらを並べ替えることができ、今

extension Person: Comparable { 
    public static func ==(lhs: Person, rhs: Person) -> Bool { 
     return lhs.lastName == rhs.lastName && lhs.firstName == rhs.firstName 
    } 

    public static func < (lhs: Person, rhs: Person) -> Bool { 
     // if lastnames are the same, compare first names, 
     // otherwise we're comparing last names 

     if lhs.lastName == rhs.lastName { 
      return lhs.firstName < rhs.firstName 
     } else { 
      return lhs.lastName < rhs.lastName 
     } 
    } 
} 

:このカスタムタイプがソート可能にするために、あなたはそれがComparableプロトコルに準拠します

ここで、上記は、オプションの比較方法に関する暗黙の疑問を避けていることは間違いありません。したがって、以下は、firstNamelastNameがオプションである例です。しかし、むしろ?または!を置く場所を心配するよりも、私は、例えばnil -coalescing演算子、??、またはswitch文を、使用したい:

struct Person { 
    let lastName: String? 
    let firstName: String? 
} 

extension Person: Comparable { 
    public static func ==(lhs: Person, rhs: Person) -> Bool { 
     return lhs.lastName == rhs.lastName && lhs.firstName == rhs.firstName 
    } 

    public static func < (lhs: Person, rhs: Person) -> Bool { 
     // if lastnames are the same, compare first names, 
     // otherwise we're comparing last names 

     var lhsString: String? 
     var rhsString: String? 
     if lhs.lastName == rhs.lastName { 
      lhsString = lhs.firstName 
      rhsString = rhs.firstName 
     } else { 
      lhsString = lhs.lastName 
      rhsString = rhs.lastName 
     } 

     // now compare two optional strings 

     return (lhsString ?? "") < (rhsString ?? "") 

     // or you could do 
     // 
     // switch (lhsString, rhsString) { 
     // case (nil, nil): return false 
     // case (nil, _): return true 
     // case (_, nil): return false 
     // default: return lhsString! < rhsString! 
     // } 
    } 
} 

switch文はnilの取り扱いに関するより明示的です値(例えば、nilは省略可能な値の前後にソートされています)が必要な場合は、nilの値と空の文字列を区別します。 nilコアレーシング演算子は簡単です(そして、IMHO、エンドユーザーにとってより直感的ですが)、必要に応じてswitchアプローチを使用できます。

関連する問題