在 Swift 中按每个 ID 的最大值过滤/排序

问题描述 投票:0回答:1

我有一个结构如下的对象数组:

{
  id: String,
  userId: String,
  distance: Double,
  time: Double
}

在数组中,同一用户 ID 在相同距离内可以有多个条目。例如,数组可能是:

[{id: "1", userId: "1", distance: 100, time 18.7}, {id: "2", userId: "1", distance: 100, time : 18.5}, 
{id: "3", userId: "2", distance: 100, time: 18.2}, {id: "4", userId: "2", distance: 200, time: 41.0}]

我想对数组进行过滤和排序,以便数组仅包含每个用户特定距离的最快时间。因此,如果我想使用上面的数组查找 100 次,它只会返回:

[{id: "3", userId: "2", distance: 100, time: 18.2}, {id: "2", userId: "1", distance: 100, time: 18.5}] 

我知道我可以使用 .filter 将其减少到 100 次,并使用 .sort 来按顺序获取时间,但我不知道如何限制每个 userId 1 个条目

arrays swift sorting
1个回答
0
投票

虽然像

sort
filter
map
这样的操作很有用并且可以简化代码,但它们都会迭代数组。

使用数组“操作”,您需要:

  • filter
    仅包含所需距离的数组
  • sort
    按用户 ID 和时间排列的数组
  • 使用
    compactMap
    仅返回每个用户的第一次(由于排序,您知道每个用户的第一次是最快的)
  • 按时间对“第一次”数组进行排序

这涉及迭代数组(或其子集)两次并对其进行两次排序。

struct DistanceTime {
    let id: String
    let userId: String
    let distance: Double
    let time: Double
}

let times = [DistanceTime(id: "1", userId: "1", distance: 100, time: 18.7), DistanceTime(id: "2", userId: "1", distance: 100, time : 18.5),
DistanceTime(id: "3", userId: "2", distance: 100, time: 18.2), DistanceTime(id: "4", userId: "2", distance: 200, time: 41.0)]

func fastestTimesMap(for distance: Double, from distanceTimes:[DistanceTime]) -> [DistanceTime] {
    
    let filteredTimes = distanceTimes.filter { dt in
        return dt.distance == distance
    }
    
    let sortedTimes = filteredTimes.sorted { dt1, dt2 in
        if dt1.userId != dt2.userId {
            return dt1.userId < dt2.userId
        } else {
            return dt1.time < dt2.time
        }
    }
    
    var currentUser: String? = nil
    
    let output = sortedTimes.compactMap { dt in 
        if dt.userId != currentUser {
            currentUser = dt.userId
            return dt
        } else {
            return nil
        }
    }
    
    return output.sorted { dt1, dt2 in
        return dt1.time < dt2.time
    }
}

let output = fastestTimesMap(for: 100, from: times)

另一种方法是使用

for
循环将数组迭代为:

  • 筛选您感兴趣的距离
  • 确定每个用户的最快时间

循环完成后,您仍然需要按

time
对缩减后的数组进行排序,以找到最快的时间:

func fastestTimes(for distance: Double, from distanceTimes:[DistanceTime]) -> [DistanceTime] {
    var times=[String:DistanceTime]()
    for dt in distanceTimes {
        if dt.distance == distance {
            if (times[dt.userId] == nil) {
                times[dt.userId] = dt
            }
            if dt.time < times[dt.userId]!.time {
                times[dt.userId] = dt
            }
        }
    }
    return Array(times.values).sorted { dt1, dt2 in 
        return dt1.time < dt2.time
    }
}

let output = fastestTimes(for: 100, from: times)

不仅代码更少,而且您现在只需遍历一次完整数组并对缩减后的数组进行一次排序。

© www.soinside.com 2019 - 2024. All rights reserved.