【问题标题】:Fetch data from an array with elements of second array从具有第二个数组元素的数组中获取数据
【发布时间】:2020-03-15 04:42:30
【问题描述】:

我有一个包含所有用户数据的数组“users”,第二个数组“userIds”包含用户 ID。我必须使用“userIds”数组从“users”数组中获取用户

struct User {
    let name: String
    let id: Int
}

let users: [User] = [User(name: "a", id: 1), 
                     User(name: "b", id: 2), 
                     User(name: "c", id: 3), 
                     User(name: "d", id: 4), 
                     User(name: "d", id: 5)]

let userIds = [2,3,2,5]

我想要的结果数组是:

[User(name: "b", id: 2),
 User(name: "c", id: 3),
 User(name: "b", id: 2),
 User(name: "d", id: 5)]

所以它可以根据“userIds”中的数据有重复的数据。

现在我尝试使用高阶函数filter:

let result = users.filter { (user) -> Bool in
    return userIds.contains(user.id)
}

但这会删除重复的数据,输出是:

[User(name: "b", id: 2),
 User(name: "c", id: 3),
 User(name: "d", id: 5)]

我尝试过的一种方法是使用 for 循环:

var result = [User]()

for i in userIds {
    result.append(users.filter({ $0.id == i }).first!)
}

它提供了所需的输出,但如果有更好的方法,请提出建议。

【问题讨论】:

  • 循环对我来说似乎是一个很好的解决方案。这对我来说不是过滤,而是使用请求(array2)从源(array1)获取
  • 感谢您的建议@JoakimDanielson。请看我添加的答案。
  • 对于array1,您可能应该使用结构而不是字典。否则,您将陷入强制转换、类型错误和崩溃的无底坑。
  • @Alexander-ReinstateMonica:它只是项目中的结构。为了提问,我在操场上创建了一个示例。

标签: arrays swift xcode filter


【解决方案1】:

您可以使用first(where:) 搜索users 来解决此问题:

let result = userIds.compactMap { desiredDataValue in
    users.first(where: { $0.id == desiredDataValue })
}

但是,如果您经常这样做,那么如果您构建一个允许通过“id”值快速查找的数据结构,它可能会加快速度。您应该自己比较一下性能,看看您是否足够/频繁地这样做是否值得:

let dictsByData = Dictionary(uniqueKeysWithValues:
    users
        .lazy
        .map { dict in
            (key: dict.id, value: dict)
        }
)

let result = userIds.compactMap { desiredDataValue in dictsByData[desiredDataValue]! }
result.forEach { print($0) }

【讨论】:

  • 非常感谢朋友。我喜欢创建数据结构的想法,它很快。除了一件事,我使用的是compactMap 而不是map。
  • @Amit 我不建议这样做。我知道compactMap 可能感觉就像您“正确处理选项”一样,因为您看不到任何!。但实际上你正在做的是将一个响亮的明显失败(崩溃)变成一个微妙的无声失败(你的结果中缺少元素)。有时这可能是合适的,但我认为最好是强制展开(如果您确定 array1 应该始终与 array2 中的值匹配),或者保留 nils 并处理他们以后。
  • 是的,你是对的。但是,array1 始终与 array2 中的值匹配。但我仍然会在集成到项目之前检查这两种情况。再次感谢好友。
  • 还有一件事,你知道这个问题被否决的原因吗?
  • @Amit 通常,将诸如“userArray”之类的名称命名为一个坏主意。 “阵列”冷只是通过复数来传达:users。而像userDict 这样的东西可以称为usersById,它显示了键和值之间的确切关系
【解决方案2】:

在这个博客的帮助下挖掘了更多之后:

我试过这样做:

let results = userIds.compactMap { (int) -> User? in
    var matchedUser: User?
    if users.contains(where: { (user) -> Bool in
        if user.id == int {
            matchedUser = user
        }
        return user.id == int
    }) {
        return matchedUser
    }
    return nil
}

在操场上,我检查了代码执行的计数:

与“for”循环相比,计数似乎更少。

【讨论】:

    猜你喜欢
    • 2019-11-28
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    • 1970-01-01
    • 2021-12-22
    • 2016-07-27
    相关资源
    最近更新 更多