0

I found online how to sort an array based off another array and it works flawlessly

let english = ["June 12, 2019", "August 12, 2018", "June 1, 2018", "July 18, 2018", "May 4, 2018"]
let ints = [3, 5, 4, 1, 2]
let doubles = [3.0, 5.0, 4.0, 1.0, 2.0]
let roman = ["III", "V", "IV", "I", "II"]

let offsets = english.enumerated().sorted { $0.element < $1.element }.map { $0.offset }

let sorted_english = offsets.map { english[$0] }
let sorted_ints = offsets.map { ints[$0] }
let sorted_doubles = offsets.map { doubles[$0] }
let sorted_roman = offsets.map { roman[$0] }

print(sorted_english)
print(sorted_ints)
print(sorted_doubles)
print(sorted_roman)

It prints the following

["August 12, 2018", "July 18, 2018", "June 1, 2018", "June 12, 2019", "May 4, 2018"]
[5, 1, 4, 3, 2]
[5.0, 1.0, 4.0, 3.0, 2.0]
["V", "I", "IV", "III", "II"]

The english array is sorted by alphabetically. I want to sort that array by date. Here is the code I have that will do that

let formatter : DateFormatter = {
    let df = DateFormatter()
    df.locale = Locale(identifier: "en_US_POSIX")
    df.dateFormat = "MMMM yyyy"
    return df
}()
let sortedMonthArray = english.sorted( by: { formatter2.date(from: $0)! < formatter2.date(from: $1)! })

How can I sort the other arrays based on the sortedMonthArray?

8
  • 1
    Is this just an exercise or do you have a real need for this? I ask because you should only have one array containing a struct. And your dates should be Date, not String. Commented Jul 24, 2018 at 0:06
  • No it's not an exercise. I'm making an app, and this is the last piece that I need.There is a reason that my dates are strings at this point in my project, but it would take to long to explain. Commented Jul 24, 2018 at 0:22
  • 1
    Dates should be Date. The only time they should be a string is to display it to the user. Commented Jul 24, 2018 at 0:33
  • 1
    Converting date strings to dates is a fairly expensive operation. The best sorting algorithms take n • log(n) time. By converting your date strings to dates in the sort, you are adding 2 • n • log(n) date-to-string conversions to your sort operation, which will slow it down signficantly. rmaddy is right on both counts. Convert this to a single array of structs, and store the dates as Date objects. Date Objects and date strings, if you must, but don't try to sort date strings by converting them to Date objects on each comparison. Commented Jul 24, 2018 at 1:32
  • 1
    I just ran a test. Sorting an array of 10,000 Date objects took ≈0.012 seconds. Sorting an array of 10,000 date strings as you do above by converting each date in the body of the sort function took ≈14.497 seconds, or ≈1177 times longer. Yes, over a thousand times longer. sorting an array of 100,000 date strings takes so long that I gave up on it. (Ok, I ran it. It took over 3 minutes, or about 1287 times longer than sorting the same-sized array of Date objects. The longer the array, the more the date string sort lags behind the Date sort. Commented Jul 24, 2018 at 1:58

1 Answer 1

1

You need to provide the correct date format to get formatted dates. The rest can be done as below,

    let english = ["June 12, 2019", "August 12, 2018", "June 1, 2018", "July 18, 2018", "May 4, 2018"]
    let ints = [3, 5, 4, 1, 2]
    let doubles = [3.0, 5.0, 4.0, 1.0, 2.0]
    let roman = ["III", "V", "IV", "I", "II"]

    let formatter : DateFormatter = {
        let df = DateFormatter()
        df.locale = Locale(identifier: "en_US_POSIX")
        df.dateFormat = "MMMM dd, yyyy"
        return df
    }()

    let dates = english.map({ formatter.date(from: $0) })
    let offsets = dates.enumerated().sorted( by: { $0.element! < $1.element! }).map({ $0.offset})

    let sorted_english = offsets.map { english[$0] }
    let sorted_ints    = offsets.map { ints[$0] }
    let sorted_doubles = offsets.map { doubles[$0] }
    let sorted_roman   = offsets.map { roman[$0] }

    print(sorted_english)
    print(sorted_ints)
    print(sorted_doubles)
    print(sorted_roman)

Output:

["May 4, 2018", "June 1, 2018", "July 18, 2018", "August 12, 2018", "June 12, 2019"]
[2, 4, 1, 5, 3]
[2.0, 4.0, 1.0, 5.0, 3.0]
["II", "IV", "I", "V", "III"]

Suggestion:

The above approach is cumbersome enough to suggest you a better design.

Create a struct that has all the associated members as below,

struct MyStruct {

    // MARK: - Private properties
    private var dateFormatter: DateFormatter = {
        let df = DateFormatter()
        df.locale = Locale(identifier: "en_US_POSIX")
        df.dateFormat = "MMMM dd, yyyy"
        return df
    }()

    // MARK: - Public properties
    public var date: Date!
    public var index: Int = 0
    public var value: Double = 0.0
    public var roman: String
    public var dateString: String

    // MARK: - Initialization
    init(_ dateString: String, index: Int, value: Double, roman: String) {
        self.dateString = dateString
        self.index = index
        self.value = value
        self.roman = roman
        self.date = self.dateFormatter.date(from: self.dateString)
    }
}

Now you can create a single array of MyStruct as below and sort with date,

    let data = [
        MyStruct("June 12, 2019",   index: 3, value: 3.0, roman: "III"),
        MyStruct("August 12, 2018", index: 5, value: 5.0, roman: "V"),
        MyStruct("June 1, 2018",    index: 4, value: 4.0, roman: "IV"),
        MyStruct("July 18, 2018",   index: 1, value: 1.0, roman: "I"),
        MyStruct("May 4, 2018",     index: 2, value: 2.0, roman: "II")
    ]
    let sorted = data.sorted(by: { $0.date < $1.date })
    sorted.forEach({ print("\($0.index): \($0.roman): \($0.value): \($0.dateString)")})

Result:

2: II: 2.0: May 4, 2018
4: IV: 4.0: June 1, 2018
1: I: 1.0: July 18, 2018
5: V: 5.0: August 12, 2018
3: III: 3.0: June 12, 2019
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! Very helpful. I used the struct and it works perfectly 👍🏻😃

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.