【问题标题】:Swift reduce and sum with condition ranking array使用条件排序数组快速减少和求和
【发布时间】:2019-06-15 10:56:13
【问题描述】:

我想计算胜利的次数并计算所有分数。

我愿意使用 flatmap map 和 reduce,以降低复杂性。为了安全起见,我可以通过循环获得它

问题在于,在 allMatch 中,我可以有不同的 teamID(团队可以单人或多人玩)并且顺序无关紧要(例如 teamID 1,2 等于 teamID 2,1

struct InfoMatch: Hashable {
    let teamId: Set<Int>
    let rank: Int
    let mPoints: Int
    let vPoints: Int
}

所有比赛都是数组数组,因为它返回每场比赛的每支球队的信息,在这个例子中,第一场比赛有2支球队,最后一场有3支球队

let allMatch: [[InfoMatch]] = [
    [InfoMatch(teamId:[1,2],rank:1,mPoints: 200,vPoints: 0),InfoMatch(teamId:[3,4],rank:2,mPoints: 100,vPoints: 0)],
    [InfoMatch(teamId:[1,2],rank:2,mPoints: 0,vPoints: 10),InfoMatch(teamId:[4,3],rank:1,mPoints: 0,vPoints: 20)],
    [InfoMatch(teamId:[2,1],rank:1,mPoints: 40,vPoints: 0),InfoMatch(teamId:[3,4],rank:2,mPoints: 30,vPoints: 0),InfoMatch(teamId:[5,6],rank:3,mPoints: 5,vPoints: 0)]
]
let winners = allMatch.map{$0.filter{$0.rank == 1}}
let losers = allMatch.map{$0.filter{$0.rank != 1}}

print(winners)

打印:

[[__lldb_expr_7.InfoMatch(teamId: Set([1, 2]), rank: 1, mPoints: 200, vPoints: 0)], [__lldb_expr_7.InfoMatch(teamId: Set([3, 4]), rank: 1, mPoints: 0, vPoints: 20)], [__lldb_expr_7.InfoMatch(teamId: Set([1, 2]), rank: 1, mPoints: 40, vPoints: 0)]]

我想要一个返回的数组

teamID: victoryCount: loserCount: mPoints: vPoints:

例如:

teamID:1,2 胜利次数:2 失败者次数:1 mPoints:240 vPoints:10 teamID:3,4 胜利次数:1 失败者次数:2 mPoints:130 vPoints:20 teamID:5,6 胜利次数:0 失败者次数:1 mPoints:5 vPoints:0

【问题讨论】:

  • 您在数组中使用数组是否正确?还是应该只是一个InfoMatches 的数组?
  • mPoints 和 vPoints 是什么意思?
  • 没错,数组数组,是每队每场比赛的结果。 mPoint是球队获得比赛的和的点。 vPoint 相同,但匹配类型不同。所以如果我有 mPoint,vPoint 为 0,反之亦然
  • teamID是一个数组,是不是包含了主队和客队的id?
  • Teamid 包含一组不同的玩家,例如第一项,playerid 1 和 playerid 2 是一个团队,而玩家 3 和玩家 4 是对面的团队

标签: ios swift iphone swift5


【解决方案1】:

我真的很想知道使用 flatmap map 和 reduce 是否可以降低复杂度,但是你可以这样使用reduce

首先,你说你想要teamID:victoryCount:loserCount:mPoints:vPoints:,那么你最好定义代表它的类型:

struct MatchStats {
    var teamID: Set<Int>
    var victoryCount: Int
    var loserCount: Int
    var mPoints: Int
    var vPoints: Int
}

//For convenience...
extension MatchStats {
    init(teamID: Set<Int>) {
        self.teamID = teamID
        victoryCount = 0
        loserCount = 0
        mPoints = 0
        vPoints = 0
    }
}

//For debugging...
extension MatchStats: CustomStringConvertible {
    public var description: String {
        let teamIDStr = teamID.sorted().map(String.init).joined(separator: ",")
        return "teamID:\(teamIDStr) victoryCount:\(victoryCount) loserCount:\(loserCount) mPoints:\(mPoints) vPoints:\(vPoints)"

    }
}

并在reduceflatMap中使用如下:

let teamStats: [Set<Int>: MatchStats] = allMatch.flatMap{$0}.reduce(into: [:]) {result, info in
    result[info.teamId, default: MatchStats(teamID: info.teamId)].victoryCount += info.rank == 1 ? 1 : 0
    result[info.teamId]!.loserCount += info.rank == 1 ? 0 : 1
    result[info.teamId]!.mPoints += info.mPoints
    result[info.teamId]!.vPoints += info.vPoints
}

print(teamStats.values)

输出:

[teamID:1,2 victoryCount:2 loserCount:1 mPoints:240 vPoints:10, teamID:3,4 victoryCount:1 loserCount:2 mPoints:130 vPoints:20, teamID:5,6 victoryCount:0 loserCount:1 mPoints:5 vPoints:0]

(每次调用时输出可能是随机顺序。但排序是另一个问题。)


您认为使用reduce 比这要好得多吗?

var teamStats: [Set<Int>: MatchStats] = [:]
for match in allMatch {
    for info in match {
        teamStats[info.teamId, default: MatchStats(teamID: info.teamId)].victoryCount += info.rank == 1 ? 1 : 0
        teamStats[info.teamId]!.loserCount += info.rank == 1 ? 0 : 1
        teamStats[info.teamId]!.mPoints += info.mPoints
        teamStats[info.teamId]!.vPoints += info.vPoints
    }
}

print(teamStats.values)

【讨论】:

  • 我喜欢你的解决方案!正如指南所说,reduce 函数的复杂度为 O(n),其中 n 是序列的长度。所以我认为很快就会尊重 a for inside,因为这不是 O(n)。我做错了吗?
  • @SimonePistecchia,当您阅读 Big-O 表示法时,了解 n 的含义很重要。在我的for-in-for 示例中,它是O(m × k),其中m 是外部数组的大小,k 是内部数组的平均大小。而在reduce 版本中,它是O(n),其中n = m × k。两者都具有相同的时间复杂度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-25
  • 2020-05-11
  • 2014-01-03
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 2019-02-09
相关资源
最近更新 更多