質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

3回答

1791閲覧

Swiftで多次元配列をソートしたい

ToshiyukiSato

総合スコア12

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2018/05/05 14:39

次の多次元配列を2つめの数字で昇順、降順にそれぞれ並び替えたいと考えています。

Swift

1[ 2 ["A", -10], 3 ["B", 20], 4 ["C", 10] 5]

以下の方法でソートができるのかと考え、試していますが、エラーが出てしまいます。

Swift

1Array.sorted(by: ($0[1] < $1[1])

エラーAnonymous closure argument not contained in a closure

多次元配列ではなく、タプルにしないとできないのか、どう実現すればいいのか方針が見えていません。
実装方法についてアドバイスをいただけませんでしょうか。

実現したいこと

昇順

Swift

1[ 2 ["A", -10], 3 ["C", 10], 4 ["B", 20] 5]

降順

Swift

1[ 2 ["B", 20], 3 ["C", 10], 4 ["A", -10] 5]

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

Swiftは型がきっちりした言語であることをまず認識してください。

また、operator < には、Intの比較,Stringの比較など多くの operator があり、コンパイラは型によってどのoperatorを使用するかを決定します。

提示の配列ですが、型を明示すると

swift

1let array: [Any] = [ 2 ["A", -10], 3 ["B", 20], 4 ["C", 10] 5]

です。

つまり、コンパイラが認識するarray[1]の型はIntではなくAnyです。
そのためコンパイラはどの<を使用していいのかを決定できません。

ですので、コンパイラに型を明示してあげる必要があるのです。

明示の方法はいろいろあります。強制的なアップキャストもその一つです。

強制的なアップキャストはクラッシュの可能性もありますので、強制的なアップキャストを使わないものをいくつか例示しておきます。

普通の関数を作る。

swift

1func g(lhs: [Any], rhs: [Any], f: (Int, Int) -> Bool) -> Bool { 2 3 guard let lhs = lhs[1] as? Int else { 4 5 return false 6 } 7 guard let rhs = rhs[1] as? Int else { 8 9 return false 10 } 11 12 return f(lhs, rhs) 13} 14 15print(array.sorted { g(lhs: $0, rhs: $1, f: >) }) 16print(array.sorted { g(lhs: $0, rhs: $1, f: <) })

ちょっと変わった関数を作る。

swift

1func h(f: @escaping (Int, Int) -> Bool) -> ([Any], [Any]) -> Bool { 2 3 return { lhs, rhs -> Bool in 4 5 guard let lhs = lhs[1] as? Int else { 6 7 return false 8 } 9 guard let rhs = rhs[1] as? Int else { 10 11 return false 12 } 13 14 return f(lhs, rhs) 15 } 16} 17 18 19print(array.sorted(by: h(f: >))) 20print(array.sorted(by: h(f: <)))

こういったことが面倒なので、普通は新しい型を作ってしまいます。
その方が逆に簡単になります。
例えば、

swift

1struct Info { 2 3 let name: String 4 let number: Int 5} 6extension Info: Comparable { 7 8 static func == (lhs: Info, rhs: Info) -> Bool { 9 return lhs.number == rhs.number 10 } 11 12 static func < (lhs: Info, rhs: Info) -> Bool { 13 return lhs.number < rhs.number 14 } 15} 16extension Info: CustomStringConvertible { 17 18 var description: String { 19 return "{ name: (name), number: (number) }" 20 } 21} 22 23// for this answer. 24extension Info { 25 26 init?(_ array: [Any]) { 27 guard let name = array[0] as? String else { 28 return nil 29 } 30 guard let number = array[1] as? Int else { 31 return nil 32 } 33 34 self.init(name: name, number: number) 35 } 36} 37 38let infoArray = array.compactMap { Info($0) } 39print(infoArray.sorted(by: >)) 40print(infoArray.sorted(by: <))

投稿2018/05/06 03:04

MasakiHori

総合スコア3384

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ToshiyukiSato

2018/05/06 06:08

ありがとうございます! 型に厳密であることを再認識します。 structを使ったことがなかったので、勉強を進めます。
guest

0

自己解決

回答内容を参考にさせていただきながら、多次元配列ではなくタプルにすることで解決しました。
大変助かりました、ありがとうございました!
structや強制ダウンキャストなど、勉強を進めます。

swift

1[ 2 ("A", -10), 3 ("B", 20), 4 ("C", 10) 5]

swift

1Taple.sort(by: {$0.1 < $1.1})

投稿2018/05/06 06:06

ToshiyukiSato

総合スコア12

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

面倒くさいので強制ダウンキャストしてます

swift

1let array = [ 2 ["A", -10], 3 ["B", 20], 4 ["C", 10], 5] 6print(array.sorted {($0[1] as! Int) > ($1[1] as! Int)}) 7//[["B", 20], ["C", 10], ["A", -10]] 8print(array.sorted {($0[1] as! Int) < ($1[1] as! Int)}) 9//[["A", -10], ["C", 10], ["B", 20]]

投稿2018/05/05 15:20

編集2018/05/06 03:50
gingertail

総合スコア317

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ToshiyukiSato

2018/05/06 06:09

ありがとうございます! たしかにこの方法で解決することは特に初級者である自分にとって有効そうです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問