2015-04-10 27 views
5

Mam problem z posortowaniem poniższego słownika, aby został wydrukowany najstarszą datą pierwszego zamówienia po wydrukowaniu.Jak sortować daty w słowniku?

var dayTotalDicTest: [String:Int] = 

      [ 
       "04-09-2015" : 4, 
       "04-10-2015" : 6, 
       "04-07-2015" : 8, 
       "03-28-2015" : 10, 
       "12-10-2014" : 12, 
       "12-10-2015" : 12, 

      ] 
+3

W większości języków nie można sortować kluczy w słowniku. To nie jest punkt słownika. Słownik służy do wstawiania i pobierania w stałym czasie. I dla kluczy, które nie są liczbami całkowitymi. Jeśli umieścisz pary wartości kluczy w liście, możesz je posortować. –

+0

dayTotalArrayTest nie jest tablicą, jest słownikiem. Nie możesz tak naprawdę posortować słownika –

Odpowiedz

7

edit/update: Xcode 8.2.1 • Swift 3.0.2

extension String { 
    static let shortDateUS: DateFormatter = { 
     let formatter = DateFormatter() 
     formatter.calendar = Calendar(identifier: .iso8601) 
     formatter.locale = Locale(identifier: "en_US_POSIX") 
     formatter.dateStyle = .short 
     return formatter 
    }() 
    var shortDateUS: Date? { 
     return String.shortDateUS.date(from: self) 
    } 
} 

let dayTotalDicTest: [String:Int] = [ 
    "04-09-2015" : 4, 
    "04-10-2015" : 6, 
    "04-07-2015" : 8, 
    "03-28-2015" : 10, 
    "12-10-2014" : 12, 
    "12-10-2015" : 12] 

let myArrayOfTuples = dayTotalDicTest.sorted{ 
    guard let d1 = $0.key.shortDateUS, let d2 = $1.key.shortDateUS else { return false } 
    return d1 < d2 
} 

print(myArrayOfTuples) // [("12-10-2014", 12), ("03-28-2015", 10), ("04-07-2015", 8), ("04-09-2015", 4), ("04-10-2015", 6), ("12-10-2015", 12)]\n" 

for tuple in myArrayOfTuples { 
    print(tuple) 
} 
+0

Dokładnie to, czego potrzebowałem, dziękuję!Naprawiono również problemy z tekstem w pytaniu, jeszcze raz dziękuję. – JideO

+0

Serdecznie zapraszamy –

+0

@LeoDabus Problem w tym, że to podejście do rozszerzenia jest okropnie nieefektywne. Zdecydowanie nie należy tworzyć nowych formatów dat w metodzie rozszerzenia. Szczerze mówiąc, nie powinieneś nawet nazywać 'dateFromString' wewnątrz" sortowanego "zamknięcia. Jeśli masz dużą tablicę (powiedzmy 1000 ciągów znaków), ten algorytm jest około 200 razy wolniejszy niż inne podejścia. Twoje rozwiązanie jest dobre dla trywialnie małych tablic, ale przy większych tablicach jest to bardzo nieefektywne. – Rob

-1

Twoje terminy są struny, więc są one klasyfikowane według string zasad sortowania. Zmień format na yyyy-MM-dd i powinny one być poprawnie sortowane.

Zakłada to, że możesz przestawić pary wartości klucza w słowniku na pierwszym miejscu.

0

Słowniki nie mogą być sortowane, więc musisz przekonwertować je na tablicę. Funkcja map może zrobić to za Ciebie. Ponadto ciągi nie mogą być sortowane tak, jak to przewidziano, więc albo trzeba zmienić strukturę ciągu na format yyyy-MM-dd, albo przekonwertować go na datę.

Ale kiedy już to zrobisz, możesz posortować tablicę. Na przykład za pomocą programowania funkcyjnego w Swift, można zrobić coś jak poniżej, który wykorzystuje map przekonwertować słownika do tablicy krotek, a następnie używa sorted uporządkować je, używając NSDateFormatter przekonwertować ciągi do dat:

var dayTotalDictionary: [String:Int] = [ 
    "04-09-2015" : 4, 
    "04-10-2015" : 6, 
    "04-07-2015" : 8, 
    "03-28-2015" : 10, 
    "12-10-2014" : 12, 
    "12-10-2015" : 12 
] 

let formatter = NSDateFormatter() 
formatter.dateFormat = "MM-dd-yyyy" 

let dayTotalArray = map(dayTotalDictionary) { ($0, $1) } 
    .sorted() { formatter.dateFromString($0.0)!.compare(formatter.dateFromString($1.0)!) == .OrderedAscending } 

Mimo że cieszy się pewną prostotą, jest to prawdopodobnie mało wydajna metoda, wymagająca więcej niż potrzeba. Tak, pewnie bym mieć funkcja map dodać obiekt NSDate do tablicy krotek, a następnie sorted mogą skorzystać z NSDate obiektu, który już tam jest:

let dayTotalArray = map(dayTotalDictionary) { (formatter.dateFromString($0)!, $0, $1) } // in Swift 2.0, use `dayTotalDictionary.map()` 
    .sorted() { ($0.0 as NSDate).compare($1.0 as NSDate) == .OrderedAscending }   // in Swift 2.0, use `sort` 
    .map() { (_, dateString, dayTotal) in (dateString, dayTotal) } 

To ostateczna map wyciąga przedmiot NSDate, ale wyraźnie nie musisz tego robić, jeśli dobrze trzymasz NSDate w krotce.

2

W Swift 3 Data obiektów są obecnie porównywalne, możemy osiągnąć to, co chcesz, co następuje:

let dayTotalDicTest: [String:Int] = [ 
    "04-09-2015" : 4, 
    "04-10-2015" : 6, 
    "04-07-2015" : 8, 
    "03-28-2015" : 10, 
    "12-10-2014" : 12, 
    "12-10-2015" : 12] 

//Create a date formatter to convert our date strings to Date objects 
let df = DateFormatter() 
df.dateFormat = "MM-dd-yyyy" 

let sortedArrayOfDicts = dayTotalDicTest 
    //First map to an array tuples: [(Date, [String:Int]] 
    .map{(df.date(from: $0.key)!, [$0.key:$0.value])} 

    //Now sort by the dates, using `<` since dates are Comparable. 
    .sorted{$0.0 < $1.0} 

    //And re-map to discard the Date objects 
    .map{$1} 

for item in sortedArrayOfDicts { 
    print(item) 
} 

Powyższy kod służy do jednorazowego odwzorowania par klucz/wartość na krotki, gdzie pierwszym elementem jest obiekt Date, a drugi wpis w krotce jest jednoczęściowym słownikiem zawierającym oringinalną parę klucz/wartość. Następnie sortuje tablicę krotek, a następnie odwzorowuje posortowaną tablicę, aby wyodrębnić pary klucz/wartość, a więc pozostaje tylko tablica jednoelementowych słowników z oryginalnej struktury danych.

Podczas sortowania, chcesz uniknąć kosztownych operacji podczas operacji porównywania sortowania. Konwersja łańcuchów daty na daty jest dość powolna. Wykonanie tej konwersji podczas każdego porównywania w sortowaniu jest wyjątkowo nieefektywne, ponieważ porównuje się każdy element w tablicy z wieloma innymi elementami, co powoduje ciągłe konwersje ciągów do daty.