Issue #672

Supposed we want to stitch magazines array into books array. The requirement is to sort them by publishedDate, but must keep preferredOrder of books. One way to solve this is to declare an enum to hold all possible cases, and then do a sort that check every possible combination

struct Book {
    let preferredOrder: Int
    let publishedDate: Date
}

struct Magazine {
    let publishedDate: Date
}

enum StitchItem {
    case book(Book)
    case magazine(Magazine)
}

func stitch(_ books: [Book], magazines: [Magazine]) -> [StitchItem] {
    let items = books.map({ StitchItem.book($0) }) + magazines.map({ StitchItem.magazine($0) })
    return items.sorted(by: { book, magazine in
        switch (book, magazine) {
        case let (.book(b1), .book(b2)):
            return b1.preferredOrder < b2.preferredOrder
        case let (.book(book), .magazine(magazine)):
            if book.publishedDate == magazine.publishedDate {
                return true
            } else {
                return book.publishedDate < magazine.publishedDate
            }
        case let (.magazine(magazine), .book(book)):
            if book.publishedDate == magazine.publishedDate {
                return false
            } else {
                return book.publishedDate < magazine.publishedDate
            }
        case let (.magazine(m1), .magazine(m2)):
            return m1.publishedDate < m2.publishedDate
        }
    })
}

The above sort function declares the intention but Swift just sort instead of trying to fully meet our requirements.

A manual solution is to sort each array first then use while loop to insert.

func stitch(_ books: [Book], magazines: [Magazine]) -> [StitchItem] {
    let books = books
        .sorted(by: { $0.preferredOrder < $1.preferredOrder })
    let magazines = magazines
        .sorted(by: sortmagazines)

    var bookIndex = 0
    var magazineIndex = 0
    var results: [StitchItem] = []
    while (bookIndex < books.count && magazineIndex < magazines.count) {
        let book = books[bookIndex]
        let magazine = magazines[magazineIndex]
        if book.publishedDate < magazine.publishedDate {
            results.append(StitchItem.book(book))
            bookIndex += 1
        } else {
            results.append(StitchItem.magazine(magazine))
            magazineIndex += 1
        }
    }

    while (bookIndex < books.count) {
        let book = books[bookIndex]
        results.append(StitchItem.book(book))
        bookIndex += 1
    }

    while (magazineIndex < magazines.count) {
        let magazine = magazines[magazineIndex]
        results.append(StitchItem.magazine(magazine))
        magazineIndex += 1
    }

    return results
}

Updated at 2020-08-31 12:19:33