Swift: сортировка массива объектов по алфавиту

138

У меня есть это:

class Movies {
  Name:String
  Date:Int
}

и массив [Фильмы]. Как отсортировать массив в алфавитном порядке по имени? Я пробовал:

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

и

movieArr = sorted(movieArr)

но это не работает, потому что у меня нет доступа к атрибуту name в Movies.

Иона Руффер
источник

Ответы:

297

В закрытии, которое вы передаете sort, сравните свойства, по которым вы хотите отсортировать. Как это:

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

или следующее в случаях, которые вы хотите обойти:

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

Sidenote: обычно только шрифты начинаются с заглавной буквы; Я бы порекомендовал использовать 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)
Майк С
источник
Спасибо, я только начинаю со Swift, и я не знал об использовании крышек.
cdpalmer
1
используйте movies.sort вместо movies.sorted @Mike S
Оскариагон
1
спасибо за объяснение Улучшено мое редактирование, должно быть в порядке, пожалуйста, посмотрите :)
Julian Król
8
Осторожно, это не будет работать при сортировке строки, которая может быть или не быть написана заглавными буквами. Сравнение .lowercaseStringрешит эту проблему.
Матье Риглер
2
@EricAya Обратите внимание, что это sortedснова в Swift 3: D.
dvp.petrov
45

С 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]
 */
Imanou Petit
источник
Эй, есть ли разница? между 2 и 3 (кроме movies.sorted(by: <)и movies.sorted())?
Камалдип Сингх Бхатия
sorted(by:)и sorted()два разных метода. Вы можете использовать array.sorted()в качестве альтернативы для array.sorted(by: <).
Imanou Petit
Да, просто спрашивая в случае определения класса, нужно ли что-то менять? Я имею в виду, можем ли мы иметь одинаковое определение класса для обоих sorted(by:)и sorted()?
Камалдип Сингх Бхатия
1
Да, у вас может быть такая же реализация вашего класса / структуры, которая в любом случае должна соответствовать Comparableпротоколу.
Imanou Petit
У меня есть массив с customObject, когда я смотрю в возрастающем порядке, он не закорочен надлежащим образом. "1" "14""28""31""4""42""49"
Крунал Нагвадия
16
let sortArray =  array.sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
m.alqadi
источник
добавление .lowercased () сработало для меня после длительного периода попыток. Я не понимаю почему, так как весь текст был написан в нижнем регистре с самого начала.
Том Таллак Солбу
при использовании lowercased () все имена в нижнем регистре изменятся на отсортированные должным образом :)
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) })
CSE 1994
источник
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!
    }*
Мухаммед Ахмад
источник