Swift: сортування масиву об’єктів за алфавітом


137

У мене це:

class Movies {
  Name:String
  Date:Int
}

і масив [Фільми]. Як сортувати масив в алфавітному порядку за назвою? Я спробував:

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

і

movieArr = sorted(movieArr)

але це не працює, тому що я не отримую доступу до атрибута імені Movies.

Відповіді:


297

Під час закриття, до якого ви переходите sort, порівняйте властивості, за якими потрібно сортувати. Подобається це:

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

або наступне у випадках, коли ви хочете обійти справи:

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

Сторона: Зазвичай лише типи починаються з великої літери; Я б рекомендував використовувати nameі date, не Nameі Date.


Наприклад, на ігровому майданчику:

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 буде в порядку [movieA, movieB, movieC]

Swift5 оновлення

channelsArray = channelsArray.sorted { (channel1, channel2) -> Bool in
            let channelName1 = channel1.name
            let channelName2 = channel2.name
            return (channelName1.localizedCaseInsensitiveCompare(channelName2) == .orderedAscending)

Дякую, я тільки починаю зі Свіфта, і я не знав про використання закривань.
cdpalmer

1
використовуйте films.sort замість movies.sorted @Mike S
Оскаріягон

1
дякую за пояснення. Покращив мою редагування, має бути добре, будь ласка, подивіться :)
Julian Król

8
Обережно, це не спрацює при сортуванні рядків, які можуть бути, а можуть і не використовуватись з великої літери. Порівняння .lowercaseStringволі вирішить цю проблему.
Матьє Ріглер

2
@EricAya Зауважте, що sortedзнову у Swift 3: D.
dvp.petrov

44

За допомогою Swift 3 ви можете вибрати один із наступних способів вирішити свою проблему.


1. Використання sorted(by:​)з Movieкласом, який не відповідає Comparableпротоколу

Якщо ваш Movieклас не відповідає Comparableпротоколу, ви повинні в ході закриття вказати властивість, для якого ви хочете використовувати sorted(by:​)метод Array .

Movie декларація класу:

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
    }

}

Використання:

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. Використання sorted(by:​)з Movieкласом, який відповідає Comparableпротоколу

Однак, зробивши свій Movieклас відповідним Comparableпротоколу, ви можете мати набагато коротший код, коли хочете використовувати sorted(by:​)метод Array .

Movie декларація класу:

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
    }

}

Використання:

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. Використання sorted()з Movieкласом, який відповідає Comparableпротоколу

Зробивши ваш Movieклас відповідним Comparableпротоколу, ви можете використовувати sorted()метод Array як альтернативу sorted(by:​).

Movie декларація класу:

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
    }

}

Використання:

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]
 */

Гей, чи є різниця між 2-м і 3-м (крім movies.sorted(by: <)і movies.sorted())?
Kamaldeep singh Bhatia

sorted(by:)і sorted()є двома різними методами. Ви можете використовувати array.sorted()як альтернативу для array.sorted(by: <).
Іману Петі

Так, просто запитуючи у випадку визначення класу, чи потрібно щось змінювати? Я маю на увазі, чи можемо ми мати однакове визначення класу для обох sorted(by:)і sorted()?
Kamaldeep singh Bhatia

1
Так, ви можете мати ту саму реалізацію свого класу / структури, яка, у будь-якому випадку, повинна відповідати Comparableпротоколу.
Imanou Petit

У мене є масив з customObject, коли я шнурую у порядку зростання, він не замикається належним чином. "1" "14""28""31""4""42""49"
Krunal Nagvadia

16
let sortArray =  array.sorted(by: { $0.name.lowercased() < $1.name.lowercased() })

додавання .lowercased () працював для мене після тривалого періоду спроб. Я не розумію, чому, оскільки для початку всі тексти мали нижню літеру.
Том Таллак Солбу

при використанні downcased () змінить усі імена на малі регістри, щоб правильно відсортовано :)
m.alqadi

14

Для тих, хто використовує Swift 3, еквівалентним методом прийнятої відповіді є:

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

1

Відсортований масив Swift 4.2

arrayOfRaces = arrayOfItems.sorted(by: { ($0["raceName"] as! String) < ($1["raceName"] as! String) })

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!
    }*
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.