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.