Szybko posortuj tablicę obiektów niestandardowych według wartości właściwości


520

powiedzmy, że mamy niestandardową klasę o nazwie imageFile i ta klasa zawiera dwie właściwości.

class imageFile  {
    var fileName = String()
    var fileID = Int()
}

wiele z nich przechowywanych w tablicy

var images : Array = []

var aImage = imageFile()
aImage.fileName = "image1.png"
aImage.fileID = 101
images.append(aImage)

aImage = imageFile()
aImage.fileName = "image1.png"
aImage.fileID = 202
images.append(aImage)

pytanie brzmi: jak mogę posortować tablicę obrazów według ASC lub DESC „fileID”?


Odpowiedzi:


940

Najpierw zadeklaruj swoją tablicę jako tablicę maszynową, aby móc wywoływać metody podczas iteracji:

var images : [imageFile] = []

Następnie możesz po prostu zrobić:

Swift 2

images.sorted({ $0.fileID > $1.fileID })

Swift 3+

images.sorted(by: { $0.fileID > $1.fileID })

Powyższy przykład podaje porządek sortowania desc


1
Brakowało mi części deklaracji tablicy, wykonało to podstęp Array <imageFile>.
mohacs

1
@AlexWayne Mam NSManagedObjectpodklasę o nazwie CheckInAndOut . W osobnym pliku zadeklarowałem tablicę typową dla obiektów tego typu, a gdy próbuję ją posortować , pojawia się błąd Nie można znaleźć elementu członkowskiego . Wiesz, dlaczego to jest?
Isuru

3
Znalazłem mój problem. Najwyraźniej tablica nie była tablicą maszynową. W każdym razie mam nowy problem. Jak mogę posortować tablicę według wielu właściwości? Powiedzieć, że 2 Własności jak firstNamei lastNamew tablicy Personobiektów. Najpierw chcę uporządkować go firstNamei potem lastName. Jak mogę to zrobić?
Isuru,

12
czy teraz musisz to zrobić images.sortInPlace({ $0.fileID > $1.fileID })?
Taylor M

13
na wypadek, gdyby ktoś zastanawiał się nad tym samym: odpowiedź da porządek malejący
Danny Wang

223

[ Zaktualizowano dla Swift 3 z sortowaniem (według :) ] To, wykorzystując końcowe zamknięcie:

images.sorted { $0.fileID < $1.fileID }

gdzie używasz odpowiednio <lub w >zależności od ASC lub DESC. Jeśli chcesz zmodyfikować imagestablicę , użyj następujących poleceń:

images.sort { $0.fileID < $1.fileID }

Jeśli zamierzasz to robić wielokrotnie i wolisz zdefiniować funkcję, jednym ze sposobów jest:

func sorterForFileIDASC(this:imageFile, that:imageFile) -> Bool {
  return this.fileID > that.fileID
}

a następnie użyj jako:

images.sort(by: sorterForFileIDASC)

jak mogę pozwać to za pomocą ciągu? muszę posortować ciąg według jego długości
Muneef M

@MuneefM właśnie zwraca string1.length <string2.length
Surjeet Rajput,

sortnie kompiluje się już z tą składnią w Xcode 8. Xcode 8 mówi, że $0.fileID < $1.fileIDprodukuje Bool, a nie Wynik Porównawczy.
Crashalot

3
Kod tej odpowiedzi działa dobrze w Xcode8; jeśli masz błąd, opublikuj nowe pytanie.
GoZoner,

Czy mogę tego również użyć do sortowania według porównań, na przykład sortowania tablic według dni tygodnia? Jeśli tak to jak?
Kristofer

53

Prawie każdy daje jak bezpośrednio, pozwól mi pokazać rozwój:

możesz użyć metod instancji Array:

// general form of closure
images.sortInPlace({ (image1: imageFile, image2: imageFile) -> Bool in return image1.fileID > image2.fileID })

// types of closure's parameters and return value can be inferred by Swift, so they are omitted along with the return arrow (->)
images.sortInPlace({ image1, image2 in return image1.fileID > image2.fileID })

// Single-expression closures can implicitly return the result of their single expression by omitting the "return" keyword
images.sortInPlace({ image1, image2 in image1.fileID > image2.fileID })

// closure's argument list along with "in" keyword can be omitted, $0, $1, $2, and so on are used to refer the closure's first, second, third arguments and so on
images.sortInPlace({ $0.fileID > $1.fileID })

// the simplification of the closure is the same
images = images.sort({ (image1: imageFile, image2: imageFile) -> Bool in return image1.fileID > image2.fileID })
images = images.sort({ image1, image2 in return image1.fileID > image2.fileID })
images = images.sort({ image1, image2 in image1.fileID > image2.fileID })
images = images.sort({ $0.fileID > $1.fileID })

Aby uzyskać szczegółowe wyjaśnienie dotyczące zasady sortowania, zobacz Sorted Function .


Czy mogę tego również użyć do sortowania według porównań, na przykład sortowania tablic według dni tygodnia? Jeśli tak to jak?
Kristofer

Dziękujemy za opublikowanie odpowiedzi, która pokazuje, jak działa zamknięcie, zamiast zakładać, że czytelnicy rozumieją tajemniczą składnię „uproszczonego” zamknięcia!
user1118321,

50

Szybki 3

people = people.sorted(by: { $0.email > $1.email })

próbowałem tego z porównaniem dat, nie mogłem go uruchomić. Dowolny pomysł?
Ebru Güngör

Nie NSDate ani String, bieżący szybki obiekt 3 Date.
Ebru Güngör

Którą właściwość Data porównujesz? Właściwość należy porównać z użytą funkcją (większą niż w moim przykładzie)
cichy

9
To jedyna przydatna odpowiedź na 2017 rok.
Fattie

@Fattie Co masz na myśli? Prawidłowa składnia topeople.sort { $0.email > $1.email }
Leo Dabus

43

W Swift 5 Arrayma dwie metody o nazwie sorted()i sorted(by:). Pierwsza metoda sorted(), ma następującą deklarację:

Zwraca posortowane elementy kolekcji.

func sorted() -> [Element]

Druga metoda sorted(by:)ma następującą deklarację:

Zwraca elementy kolekcji posortowane przy użyciu podanego predykatu jako porównania między elementami.

func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]

# 1. Sortuj w kolejności rosnącej dla porównywalnych obiektów

Jeśli typ elementu w Twojej kolekcji jest zgodny Comparable protokołem, będziesz mógł użyć go sorted()do posortowania elementów w porządku rosnącym. Poniższy kod placu zabaw pokazuje, jak używać sorted():

class ImageFile: CustomStringConvertible, Comparable {

    let fileName: String
    let fileID: Int
    var description: String { return "ImageFile with ID: \(fileID)" }

    init(fileName: String, fileID: Int) {
        self.fileName = fileName
        self.fileID = fileID
    }

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

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

}

let images = [
    ImageFile(fileName: "Car", fileID: 300),
    ImageFile(fileName: "Boat", fileID: 100),
    ImageFile(fileName: "Plane", fileID: 200)
]

let sortedImages = images.sorted()
print(sortedImages)

/*
 prints: [ImageFile with ID: 100, ImageFile with ID: 200, ImageFile with ID: 300]
 */

# 2. Sortuj według malejącej kolejności dla porównywalnych obiektów

Jeśli typ elementu w Twojej kolekcji jest zgodny Comparable protokołem, będziesz musiał użyć go sorted(by:), aby posortować elementy w porządku malejącym.

class ImageFile: CustomStringConvertible, Comparable {

    let fileName: String
    let fileID: Int
    var description: String { return "ImageFile with ID: \(fileID)" }

    init(fileName: String, fileID: Int) {
        self.fileName = fileName
        self.fileID = fileID
    }

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

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

}

let images = [
    ImageFile(fileName: "Car", fileID: 300),
    ImageFile(fileName: "Boat", fileID: 100),
    ImageFile(fileName: "Plane", fileID: 200)
]

let sortedImages = images.sorted(by: { (img0: ImageFile, img1: ImageFile) -> Bool in
    return img0 > img1
})
//let sortedImages = images.sorted(by: >) // also works
//let sortedImages = images.sorted { $0 > $1 } // also works
print(sortedImages)

/*
 prints: [ImageFile with ID: 300, ImageFile with ID: 200, ImageFile with ID: 100]
 */

# 3. Sortuj w kolejności rosnącej lub malejącej dla nieporównywalnych obiektów

Jeśli typ elementu w Twojej kolekcji NIE JEST zgodny z Comparableprotokołem, będziesz musiał użyćsorted(by:) , aby posortować elementy w porządku rosnącym lub malejącym.

class ImageFile: CustomStringConvertible {

    let fileName: String
    let fileID: Int
    var description: String { return "ImageFile with ID: \(fileID)" }

    init(fileName: String, fileID: Int) {
        self.fileName = fileName
        self.fileID = fileID
    }

}

let images = [
    ImageFile(fileName: "Car", fileID: 300),
    ImageFile(fileName: "Boat", fileID: 100),
    ImageFile(fileName: "Plane", fileID: 200)
]

let sortedImages = images.sorted(by: { (img0: ImageFile, img1: ImageFile) -> Bool in
    return img0.fileID < img1.fileID
})
//let sortedImages = images.sorted { $0.fileID < $1.fileID } // also works
print(sortedImages)

/*
 prints: [ImageFile with ID: 300, ImageFile with ID: 200, ImageFile with ID: 100]
 */

Zwróć uwagę, że Swift udostępnia również dwie metody o nazwie sort()i sort(by:)jako odpowiedniki sorted()i sorted(by:)jeśli musisz posortować swoją kolekcję na miejscu.


25

W Swift 3.0

images.sort(by: { (first: imageFile, second: imageFile) -> Bool in
    first. fileID < second. fileID
})

20

Możesz także zrobić coś takiego

images = sorted(images) {$0.fileID > $1.fileID}

więc tablica zdjęć będzie przechowywana jako posortowana


19

Szybko 2 do 4

Pierwotna odpowiedź próbowała posortować tablicę niestandardowych obiektów za pomocą jakiejś właściwości. Poniżej pokażę kilka przydatnych sposobów na wykonanie tego samego zachowania w / szybkich struktur danych!

Małe rzeczy na swojej drodze, nieznacznie zmieniłem ImageFile. Mając to na uwadze, tworzę tablicę z trzema plikami obrazów. Zauważ, że metadane są wartością opcjonalną, przekazując zero jako oczekiwany parametr.

 struct ImageFile {
      var name: String
      var metadata: String?
      var size: Int
    }

    var images: [ImageFile] = [ImageFile(name: "HelloWorld", metadata: nil, size: 256), ImageFile(name: "Traveling Salesmen", metadata: "uh this is huge", size: 1024), ImageFile(name: "Slack", metadata: "what's in this stuff?", size: 2048) ]

ImageFile ma właściwość o nazwie size. W poniższych przykładach pokażę, jak używać operacji sortowania z właściwościami takimi jak rozmiar.

najmniejszy do największego rozmiaru (<)

    let sizeSmallestSorted = images.sorted { (initial, next) -> Bool in
      return initial.size < next.size
    }

od największego do najmniejszego (>)

    let sizeBiggestSorted = images.sorted { (initial, next) -> Bool in
      return initial.size > next.size
    }

Następnie posortujemy według nazwy właściwości String. W ten sam sposób użyj sortowania, aby porównać ciągi znaków. Ale zauważ, że wewnętrzny blok zwraca wynik porównania. Ten wynik zdefiniuje sortowanie.

AZ (.orderedAscending)

    let nameAscendingSorted = images.sorted { (initial, next) -> Bool in
      return initial.name.compare(next.name) == .orderedAscending
    }

ZA (.orderedDescending)

    let nameDescendingSorted = images.sorted { (initial, next) -> Bool in
      return initial.name.compare(next.name) == .orderedDescending
    }

Następny jest mój ulubiony sposób sortowania, w wielu przypadkach będzie miał opcjonalne właściwości. Teraz nie martw się, będziemy sortować w taki sam sposób jak powyżej, z tym wyjątkiem, że musimy zająć zero! W produkcji;

Użyłem tego kodu, aby wymusić na wszystkich instancjach w mojej tablicy zerowe wartości właściwości, aby były ostatnie. Następnie uporządkuj metadane przy użyciu założonych niezapakowanych wartości.

    let metadataFirst = images.sorted { (initial, next) -> Bool in
      guard initial.metadata != nil else { return true }
      guard next.metadata != nil else { return true }
      return initial.metadata!.compare(next.metadata!) == .orderedAscending
    }

Możliwe jest dodatkowe sortowanie dla opcji. Na przykład; można wyświetlać obrazy z metadanymi i uporządkowane według rozmiaru.


1
Zasadniczo odpowiedzi są o wiele bardziej pomocne, jeśli zawierają wyjaśnienie, do czego służy kod i dlaczego rozwiązuje problem bez przedstawiania innych.
Tom Aranda,

Znacznie lepiej.
Tom Aranda,

18

Dwie alternatywy

1) Zamawianie oryginalnej tablicy za pomocą sortInPlace

self.assignments.sortInPlace({ $0.order < $1.order })
self.printAssignments(assignments)

2) Używanie alternatywnej tablicy do przechowywania uporządkowanej tablicy

var assignmentsO = [Assignment] ()
assignmentsO = self.assignments.sort({ $0.order < $1.order })
self.printAssignments(assignmentsO)

3
re 2) Jaki jest sens konstruowania pustej tablicy i odrzucania jej w następnej linii? Sugeruję użycie var assignmentsO : [Assignment]lub połączenie go w jedną linię za pomocąlet assignmentsO = self.assignments.sort({ $0.order < $1.order })
Hermann Klecker

2
Cześć Hermann! Istnieje bardzo cienka granica między pisaniem czytelnego i wydajnego kodu. W tym przypadku jedynym celem jest uczynienie go bardziej czytelnym dla społeczności;) ciesz się!
Bernauer

18

Swift 4.0, 4.1 i 4.2 Najpierw stworzyłem zmienną tablicę typu imageFile (), jak pokazano poniżej

var arr = [imageFile]()

Utwórz zmienny obraz obiektu typu imageFile () i przypisz wartość do właściwości, jak pokazano poniżej

   var image = imageFile()
   image.fileId = 14
   image.fileName = "A"

Teraz dołącz ten obiekt do tablicy arr

    arr.append(image)

Teraz przypisz różne właściwości do tego samego zmiennego obiektu, tj. Obrazu

   image = imageFile()
   image.fileId = 13
   image.fileName = "B"

Teraz ponownie dołącz obiekt obrazu do tablicy arr

    arr.append(image)

Teraz będziemy stosować porządku rosnącym na fileid nieruchomości w tablicy obiektów Arr. Użyj <symbol dla porządku rosnącego

 arr = arr.sorted(by: {$0.fileId < $1.fileId}) // arr has all objects in Ascending order
 print("sorted array is",arr[0].fileId)// sorted array is 13
 print("sorted array is",arr[1].fileId)//sorted array is 14

Teraz zastosujemy porządek malejący dla właściwości fileId w obiektach tablicowych. Użyj > symbolu dla porządku malejącego

 arr = arr.sorted(by: {$0.fileId > $1.fileId}) // arr has all objects in Descending order
 print("Unsorted array is",arr[0].fileId)// Unsorted array is 14
 print("Unsorted array is",arr[1].fileId)// Unsorted array is 13

W Swift 4.1. & 4.2 Do użytku posortowanego

let sortedArr = arr.sorted { (id1, id2) -> Bool in
  return id1.fileId < id2.fileId // Use > for Descending order
}

8

Jeśli zamierzasz sortować tę tablicę w więcej niż jednym miejscu, sensowne może być uczynienie typu tablicy Porównywalnym.

class MyImageType: Comparable, Printable {
    var fileID: Int

    // For Printable
    var description: String {
        get {
            return "ID: \(fileID)"
        }
    }

    init(fileID: Int) {
        self.fileID = fileID
    }
}

// For Comparable
func <(left: MyImageType, right: MyImageType) -> Bool {
    return left.fileID < right.fileID
}

// For Comparable
func ==(left: MyImageType, right: MyImageType) -> Bool {
    return left.fileID == right.fileID
}

let one = MyImageType(fileID: 1)
let two = MyImageType(fileID: 2)
let twoA = MyImageType(fileID: 2)
let three = MyImageType(fileID: 3)

let a1 = [one, three, two]

// return a sorted array
println(sorted(a1)) // "[ID: 1, ID: 2, ID: 3]"

var a2 = [two, one, twoA, three]

// sort the array 'in place'
sort(&a2)
println(a2) // "[ID: 1, ID: 2, ID: 2, ID: 3]"

6

Jeśli nie używasz niestandardowych obiektów, ale zamiast tego używasz typów wartości, które implementują protokół porównywalny (Int, String itp.), Możesz po prostu to zrobić:

myArray.sort(>) //sort descending order

Przykład:

struct MyStruct: Comparable {
    var name = "Untitled"
}

func <(lhs: MyStruct, rhs: MyStruct) -> Bool {
    return lhs.name < rhs.name
}
// Implementation of == required by Equatable
func ==(lhs: MyStruct, rhs: MyStruct) -> Bool {
    return lhs.name == rhs.name
}

let value1 = MyStruct()
var value2 = MyStruct()

value2.name = "A New Name"

var anArray:[MyStruct] = []
anArray.append(value1)
anArray.append(value2)

anArray.sort(>) // This will sort the array in descending order

w swift 3 itmyArray.sorted(by: >)
beryl

6

Zwrócono posortowaną tablicę z właściwości fileID w następujący sposób:

Swift 2

let sortedArray = images.sorted({ $0.fileID > $1.fileID })

Szybki 3 LUB 4

let sortedArray = images.sorted(by: { $0.fileID > $1.fileID })

Swift 5.0

let sortedArray = images.sorted {
    $0.fileID < $1.fileID
}

Działa jak urok .. pozytywnie! (Pratik Prajapati, Ahmedabad)
NSPratik

4

Robię to w ten sposób i działa:

var images = [imageFile]() images.sorted(by: {$0.fileID.compare($1.fileID) == .orderedAscending })


2

Jeśli chcesz posortować oryginalną tablicę obiektów niestandardowych. Oto inny sposób, aby to zrobić w Swift 2.1

var myCustomerArray = [Customer]()
myCustomerArray.sortInPlace {(customer1:Customer, customer2:Customer) -> Bool in
    customer1.id < customer2.id
}

Gdzie idjest liczba całkowita. Tego samego <operatora można również użyć do Stringwłaściwości.

Możesz dowiedzieć się więcej o jego wykorzystaniu, patrząc na przykład tutaj: Swift2: Pobliscy klienci


2
var students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]

students.sort(by: >)

print(students)

Wydruki: "["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"


1

Swift 3 oraz 4 i 5

Miałem pewien problem związany z małymi i dużymi literami

więc zrobiłem ten kod

let sortedImages = images.sorted(by: { $0.fileID.lowercased() < $1.fileID.lowercased() })

a następnie użyj sortedImages po tym


0

Sortuj za pomocą KeyPath

możesz sortować według KeyPathtego:

myArray.sorted(by: \.fileName, <) /* using `<` for ascending sorting */

Wdrażając to mało pomocne rozszerzenie.

extension Collection{
    func sorted<Value: Comparable>(
        by keyPath: KeyPath<Element, Value>,
        _ comparator: (_ lhs: Value, _ rhs: Value) -> Bool) -> [Element] {
        sorted { comparator($0[keyPath: keyPath], $1[keyPath: keyPath]) }
    }
}

Hope Swift doda to w najbliższej przyszłości w rdzeniu języka.


Na to pytanie już tutaj odpowiedziano stackoverflow.com/a/46601105/2303865 wraz z metodą mutacji.
Leo Dabus

wersja public extension MutableCollection where Self: RandomAccessCollection { mutating func sort<T>(_ keyPath: KeyPath<Element, T>, by areInIncreasingOrder: (T, T) throws -> Bool) rethrows where T: Comparable { try sort { try areInIncreasingOrder($0[keyPath: keyPath], $1[keyPath: keyPath]) } }}
mutująca
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.