Swift: Sortuj tablicę obiektów alfabetycznie

137

Mam to:

class Movies {
  Name:String
  Date:Int
}

i tablicę [Movies]. Jak posortować tablicę alfabetycznie według nazwy? Próbowałem:

movieArr = movieArr.sorted{ $0 < $1 }

i

movieArr = sorted(movieArr)

ale to nie działa, ponieważ nie mam dostępu do atrybutu nazwy filmów.

Jonah Ruffer
źródło

Odpowiedzi:

297

W zamknięciu, do którego przejdziesz sort, porównaj właściwości, według których chcesz sortować. Lubię to:

movieArr.sorted { $0.name < $1.name }

lub następujące w przypadkach, w których chcesz ominąć przypadki:

movieArr.sorted { $0.name.lowercased() < $1.name.lowercased() }

Uwaga dodatkowa: Zazwyczaj tylko typy rozpoczynają się wielką literą; Polecam używanie namei date, nie Namei Date.


Przykład na placu zabaw:

class Movie {
    let name: String
    var date: Int?

    init(_ name: String) {
        self.name = name
    }
}

var movieA = Movie("A")
var movieB = Movie("B")
var movieC = Movie("C")

let movies = [movieB, movieC, movieA]
let sortedMovies = movies.sorted { $0.name < $1.name }
sortedMovies

sortedMovies będzie w kolejności [movieA, movieB, movieC]

Aktualizacja Swift5

channelsArray = channelsArray.sorted { (channel1, channel2) -> Bool in
            let channelName1 = channel1.name
            let channelName2 = channel2.name
            return (channelName1.localizedCaseInsensitiveCompare(channelName2) == .orderedAscending)
Mike S.
źródło
Dzięki, dopiero zaczynam od Swift i nie wiedziałem o używaniu zamknięć.
cdpalmer
1
użyj movies.sort zamiast movies.sorted @Mike S
Oskariagon
1
dzięki za wyjaśnienie. Poprawiłem mój montaż, powinno być dobrze, zapraszam :)
Julian Król
8
Uwaga, to nie zadziała podczas sortowania ciągów znaków, które mogą być pisane wielkimi literami lub nie. Porównanie wyników .lowercaseStringrozwiąże ten problem.
Matthieu Riegler
2
@EricAya Zauważ, że sortedznowu jest w Swift 3: D.
dvp.petrov
44

Dzięki Swift 3 możesz wybrać jeden z następujących sposobów rozwiązania problemu.


1. Używanie sorted(by:​)z Movieklasą, która nie jest zgodna zComparable protokołem

Jeśli twoja Movieklasa nie jest zgodna z Comparableprotokołem, musisz określić w swoim zamknięciu właściwość, na której chcesz używać sorted(by:​)metody Array .

Movie deklaracja klasy:

import Foundation

class Movie: CustomStringConvertible {

    let name: String
    var date: Date
    var description: String { return name }

    init(name: String, date: Date = Date()) {
        self.name = name
        self.date = date
    }

}

Stosowanie:

let avatarMovie = Movie(name: "Avatar")
let titanicMovie = Movie(name: "Titanic")
let piranhaMovie = Movie(name: "Piranha II: The Spawning")

let movies = [avatarMovie, titanicMovie, piranhaMovie]
let sortedMovies = movies.sorted(by: { $0.name < $1.name })
// let sortedMovies = movies.sorted { $0.name < $1.name } // also works

print(sortedMovies)

/*
prints: [Avatar, Piranha II: The Spawning, Titanic]
*/

2. Używanie sorted(by:​)z Movieklasą zgodną z Comparableprotokołem

Jednak sprawiając, że Movieklasa jest zgodna z Comparableprotokołem, możesz mieć bardzo zwięzły kod, gdy chcesz użyć sorted(by:​)metody Array .

Movie deklaracja klasy:

import Foundation

class Movie: CustomStringConvertible, Comparable {

    let name: String
    var date: Date
    var description: String { return name }

    init(name: String, date: Date = Date()) {
        self.name = name
        self.date = date
    }

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

    static func <(lhs: Movie, rhs: Movie) -> Bool {
        return lhs.name < rhs.name
    }

}

Stosowanie:

let avatarMovie = Movie(name: "Avatar")
let titanicMovie = Movie(name: "Titanic")
let piranhaMovie = Movie(name: "Piranha II: The Spawning")

let movies = [avatarMovie, titanicMovie, piranhaMovie]
let sortedMovies = movies.sorted(by: { $0 < $1 })
// let sortedMovies = movies.sorted { $0 < $1 } // also works
// let sortedMovies = movies.sorted(by: <) // also works

print(sortedMovies)

/*
 prints: [Avatar, Piranha II: The Spawning, Titanic]
 */

3. Używanie sorted()z Movieklasą, która jest zgodna zComparable protokołem

Dostosowując Movieklasę do Comparableprotokołu, możesz użyć sorted()metody Array jako alternatywy dla sorted(by:​).

Movie deklaracja klasy:

import Foundation

class Movie: CustomStringConvertible, Comparable {

    let name: String
    var date: Date
    var description: String { return name }

    init(name: String, date: Date = Date()) {
        self.name = name
        self.date = date
    }

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

    static func <(lhs: Movie, rhs: Movie) -> Bool {
        return lhs.name < rhs.name
    }

}

Stosowanie:

let avatarMovie = Movie(name: "Avatar")
let titanicMovie = Movie(name: "Titanic")
let piranhaMovie = Movie(name: "Piranha II: The Spawning")

let movies = [avatarMovie, titanicMovie, piranhaMovie]
let sortedMovies = movies.sorted()

print(sortedMovies)

/*
 prints: [Avatar, Piranha II: The Spawning, Titanic]
 */
Imanou Petit
źródło
Hej, czy jest jakaś różnica. między 2 a 3 (z wyjątkiem movies.sorted(by: <)i movies.sorted())?
Kamaldeep singh Bhatia,
sorted(by:)i sorted()są dwiema różnymi metodami. Możesz użyć array.sorted()jako alternatywy dla array.sorted(by: <).
Imanou Petit
Tak, po prostu pytam w przypadku definicji klasy, czy musimy cokolwiek zmieniać? Chodzi mi o to, czy możemy mieć tę samą definicję klasy dla obu sorted(by:)i sorted()?
Kamaldeep singh Bhatia,
1
Tak, możesz mieć taką samą implementację swojej klasy / struktury, która w każdym przypadku musi być zgodna z Comparableprotokołem.
Imanou Petit
Mam Array z customObject, kiedy pokazuję się w porządku rosnącym, to nie jest zwarcie we właściwy sposób. "1" "14""28""31""4""42""49"
Krunal Nagvadia
16
let sortArray =  array.sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
m.alqadi
źródło
dodanie .lowercased () zadziałało dla mnie po długim okresie prób. Nie rozumiem dlaczego, ponieważ cały tekst był od początku pisany małymi literami.
Tom Tallak Solbu
użycie małych liter () spowoduje zmianę wszystkich nazw na małe, aby były posortowane poprawnie :)
m.alqadi
14

W przypadku użytkowników korzystających z języka Swift 3 równoważną metodą zaakceptowanej odpowiedzi jest:

movieArr.sorted { $0.Name < $1.Name }
Jacobo Koenig
źródło
1

Posortowana tablica Swift 4.2

arrayOfRaces = arrayOfItems.sorted(by: { ($0["raceName"] as! String) < ($1["raceName"] as! String) })
CSE 1994
źródło
0
*import Foundation
import CoreData


extension Messages {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Messages> {
        return NSFetchRequest<Messages>(entityName: "Messages")
    }

    @NSManaged public var text: String?
    @NSManaged public var date: Date?
    @NSManaged public var friends: Friends?

}

    //here arrMessage is the array you can sort this array as under bellow 

    var arrMessages = [Messages]()

    arrMessages.sort { (arrMessages1, arrMessages2) -> Bool in
               arrMessages1.date! > arrMessages2.date!
    }*
Muhammad Ahmad
źródło