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

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

ただいまの
回答率

90.76%

  • Swift

    6713questions

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

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

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 287

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

[
    ["A", -10],
    ["B", 20],
    ["C", 10]
]

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

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


エラーAnonymous closure argument not contained in a closure

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

 実現したいこと

昇順

[
    ["A", -10],
    ["C", 10],
    ["B", 20]
]

降順

[
    ["B", 20],
    ["C", 10],
    ["A", -10]
]
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+2

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

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

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

let array: [Any] = [
    ["A", -10],
    ["B", 20],
    ["C", 10]
]


です。

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

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

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

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

普通の関数を作る。

func g(lhs: [Any], rhs: [Any], f: (Int, Int) -> Bool) -> Bool {

    guard let lhs = lhs[1] as? Int else {

        return false
    }
    guard let rhs = rhs[1] as? Int else {

        return false
    }

    return f(lhs, rhs)
}

print(array.sorted { g(lhs: $0, rhs: $1, f: >) })
print(array.sorted { g(lhs: $0, rhs: $1, f: <) })

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

func h(f: @escaping (Int, Int) -> Bool) -> ([Any], [Any]) -> Bool {

    return { lhs, rhs -> Bool in

        guard let lhs = lhs[1] as? Int else {

            return false
        }
        guard let rhs = rhs[1] as? Int else {

            return false
        }

        return f(lhs, rhs)
    }
}


print(array.sorted(by: h(f: >)))
print(array.sorted(by: h(f: <)))

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

struct Info {

    let name: String
    let number: Int
}
extension Info: Comparable {

    static func == (lhs: Info, rhs: Info) -> Bool {
        return lhs.number == rhs.number
    }

    static func < (lhs: Info, rhs: Info) -> Bool {
        return lhs.number < rhs.number
    }
}
extension Info: CustomStringConvertible {

    var description: String {
        return "{ name: \(name), number: \(number) }"
    }
}

// for this answer.
extension Info {

    init?(_ array: [Any]) {
        guard let name = array[0] as? String else {
            return nil
        }
        guard let number = array[1] as? Int else {
            return nil
        }

        self.init(name: name, number: number)
    }
}

let infoArray = array.compactMap { Info($0) }
print(infoArray.sorted(by: >))
print(infoArray.sorted(by: <))

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/06 15:08

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

    キャンセル

check解決した方法

+1

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

[
    ("A", -10),
    ("B", 20),
    ("C", 10)
]
Taple.sort(by: {$0.1 < $1.1})

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

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

let array = [
    ["A", -10],
    ["B", 20],
    ["C", 10],
]
print(array.sorted {($0[1] as! Int) > ($1[1] as! Int)})
//[["B", 20], ["C", 10], ["A", -10]]
print(array.sorted {($0[1] as! Int) < ($1[1] as! Int)})
//[["A", -10], ["C", 10], ["B", 20]]

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/06 15:09

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

    キャンセル

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

  • ただいまの回答率 90.76%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Swift

    6713questions

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