【问题标题】:Sorting an array with nested tuples使用嵌套元组对数组进行排序
【发布时间】:2018-09-21 01:11:52
【问题描述】:

我正在创建包含以下元素的前 5 名分数排行榜:

玩家姓名

完成时间(完成游戏所用的时间)

总移动次数

日期戳

为此,我创建了一个带有嵌套元组的元组数组来跟踪分钟、秒和毫秒,如下所示:

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

当游戏完成时,这些值将被追加到数组中,直到它包含总共 5 个元素。

我的麻烦是我需要按完成时间升序对这个数组进行排序。由于该数组中元组的复杂嵌套性质,我似乎无法找到实现此目的的有效方法。任何帮助将不胜感激。

【问题讨论】:

  • 这是一个糟糕的数据结构,最好使用结构/类。元组不打算成为模型......

标签: arrays swift sorting nested tuples


【解决方案1】:

如果您的 completionTime 格式正确(seconds0...59 中,milliseconds0...999 中),那么您可以使用以下命令对 leaderboard 进行排序:

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

这是可行的,因为 Swift 可以比较两个元组 (1, 2, 3)(1, 2, 4)&lt;,它会比较第一个项目,如果它们相等,它将比较第二个项目,如果它们相等它将比较第三个。因此,您可以通过简单的&lt; 比较来订购它们。即使项目被标记,只要两个元组具有相同数量的元素,元素数量为 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)

【讨论】:

  • 酷。我不知道元组支持这样的比较。 (已投票)
  • 顺便说一句,leaderBoard.forEach {print($0)} 的输出将每个条目放在一个新行上,因此更具可读性。
  • 感谢@DuncanC 的建议。这更具可读性。
【解决方案2】:

sorted 函数很好地完成了这项工作。它采用一个闭包来比较数组中的两项,如果第一项小于第二项,则返回 true。

您只需要编写一个闭包,为每个完成时间计算一个值并比较它们。进行整数数学运算更快,因此以下将每个 completionTime 转换为整数毫秒并比较这些值:

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
}

【讨论】:

  • 更简单:直接比较lhs.completionTime &lt; rhs.completionTime。看我的回答。
  • 感谢您接受我的回答,但我得说@vacawama 的回答更好。它更简单、更干净。
【解决方案3】:
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)
    }
}

【讨论】:

  • 盖克。这真的很复杂,我不清楚它是否/如何工作。看我的回答。简单得多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-03
  • 1970-01-01
  • 1970-01-01
  • 2019-05-14
  • 2021-05-13
相关资源
最近更新 更多