Сортировка массива с вложенными кортежами - PullRequest
0 голосов
/ 21 сентября 2018

Я создаю таблицу лидеров из 5 лучших результатов, которая содержит следующие элементы:

Имя игрока

Время завершения (сколько времени прошло, чтобы пройти игру)

Общее количество ходов

Штамп даты

Для этого я создал массив кортежей с вложенным кортежом для отслеживания минут, секунд и миллисекунд, как показано ниже:

var leaderBoard: [(playerName: String, completionTime: (minutes: Int, seconds: Int, miliseconds: Int), totalMoves: Int, dateStamp: Date)] = []

Когда игра завершена, эти значения добавляются в массив, пока он не содержит в общей сложности 5 элементов.

Моя проблема в том, что мне нужно отсортировать этот массив по времени завершенияв порядке возрастанияИз-за сложной, вложенной природы кортежей в этом массиве я не могу найти подходящий способ сделать это.Любая помощь будет принята с благодарностью.

Ответы [ 3 ]

0 голосов
/ 21 сентября 2018

Сортированная функция прекрасно справляется с этой задачей.Он берет замыкание, которое сравнивает 2 элемента из массива и возвращает true, если первый меньше второго.

Вам просто нужно написать закрытие, которое вычисляет значение для каждого completeTime и сравнивает их.Целочисленная математика выполняется быстрее, поэтому следующий код преобразует каждое завершение в целое число миллисекунд и сравнивает эти значения:

let sortedPlayers = leaderBoard.sorted { lhs, rhs in
    let lhTime =  lhs.completionTime.minutes * 60_000 + lhs.completionTime.seconds * 1000 + 
      lhs.completionTime.miliseconds
    let rhTime =  rhs.completionTime.minutes * 60_000 + rhs.completionTime.seconds * 1000 + 
      rhs.completionTime.miliseconds
    return lhTime < rhTime
}
0 голосов
/ 21 сентября 2018

Если ваш completionTime правильно сформирован (seconds в 0...59 и milliseconds в 0...999), тогда вы можете отсортировать leaderboard с помощью:

leaderBoard.sort { $0.completionTime < $1.completionTime }

Это работает, потому что Swift может сравнивать 2 кортежа (1, 2, 3) и (1, 2, 4) с <, и он будет сравнивать первые элементы, и если они равны, он будет сравнивать вторые элементы, и если они равныон будет сравнивать третий.Таким образом, вы можете заказать их с простым < сравнением.Это работает, даже если элементы помечены, если два кортежа имеют одинаковое количество элементов, количество элементов равно 6 или меньше, а типы соответствующих элементов совпадают.


Пример:

var leaderBoard: [(playerName: String, completionTime: (minutes: Int, seconds: Int, milliseconds: Int), totalMoves: Int, dateStamp: Date)] = [
    (playerName: "Fred", completionTime: (minutes: 4, seconds: 10, milliseconds: 800), totalMoves: 3, dateStamp: Date()),
    (playerName: "Barney", completionTime: (minutes: 5, seconds: 10, milliseconds: 800), totalMoves: 3, dateStamp: Date()),
    (playerName: "Wilma", completionTime: (minutes: 4, seconds: 10, milliseconds: 801), totalMoves: 3, dateStamp: Date()),
    (playerName: "Bam Bam", completionTime: (minutes: 1, seconds: 10, milliseconds: 0), totalMoves: 3, dateStamp: Date()),
    (playerName: "Pebbles", completionTime: (minutes: 4, seconds: 10, milliseconds: 799), totalMoves: 3, dateStamp: Date())
]

leaderBoard.sort { $0.completionTime < $1.completionTime }
leaderBoard.forEach { print($0) }

Выход:

(playerName: "Bam Bam", completionTime: (minutes: 1, seconds: 10, milliseconds: 0), totalMoves: 3, dateStamp: 2018-09-21 11:17:36 +0000)
(playerName: "Pebbles", completionTime: (minutes: 4, seconds: 10, milliseconds: 799), totalMoves: 3, dateStamp: 2018-09-21 11:17:36 +0000)
(playerName: "Fred", completionTime: (minutes: 4, seconds: 10, milliseconds: 800), totalMoves: 3, dateStamp: 2018-09-21 11:17:36 +0000)
(playerName: "Wilma", completionTime: (minutes: 4, seconds: 10, milliseconds: 801), totalMoves: 3, dateStamp: 2018-09-21 11:17:36 +0000)
(playerName: "Barney", completionTime: (minutes: 5, seconds: 10, milliseconds: 800), totalMoves: 3, dateStamp: 2018-09-21 11:17:36 +0000)
0 голосов
/ 21 сентября 2018
func recordWin() {
    let newEntry: (playerName: String, completionTime: (minutes: Int, seconds: Int, miliseconds: Int), totalMoves: Int, dateStamp: Date) = (playerName, completionTime, totalMoves, dateStamp)

    if leaderBoard.count < 5 {
        leaderBoard.append(newEntry)
    }

    else {

    }

    if leaderBoard.count > 1 {
        for _ in 0...4 {
            var currentIndex = 0

            for score in leaderBoard {
                if currentIndex > 0 {
                    if score.completionTime.minutes < leaderBoard[currentIndex - 1].completionTime.minutes {
                        leaderBoard.remove(at: currentIndex)
                        leaderBoard.insert(score, at: currentIndex - 1)
                    }

                    else if score.completionTime.minutes == leaderBoard[currentIndex - 1].completionTime.minutes {
                        if score.completionTime.seconds < leaderBoard[currentIndex - 1].completionTime.seconds {
                            leaderBoard.remove(at: currentIndex)
                            leaderBoard.insert(score, at: currentIndex - 1)
                        }

                        else if score.completionTime.seconds == leaderBoard[currentIndex - 1].completionTime.seconds {
                            if score.completionTime.miliseconds < leaderBoard[currentIndex - 1].completionTime.seconds {
                                leaderBoard.remove(at: currentIndex)
                                leaderBoard.insert(score, at: currentIndex - 1)
                            }
                        }
                    }
                }

                currentIndex += 1
            }
        }
    }

    if leaderBoard.count > 5 {
        leaderBoard.removeLast()
    }

    for score in leaderBoard {
        print(score.playerName + ": " + "Completion Time: " + "Total Moves: " + score.totalMoves.description + "Completion Time: " + score.completionTime.minutes.description + ":" + score.completionTime.seconds.description + ":" + score.completionTime.miliseconds.description + " - " + score.dateStamp.description)
    }
}
...