【问题标题】:Swift add or update Array of item base on unique property id基于唯一属性 id 快速添加或更新项目数组
【发布时间】:2018-10-16 07:42:06
【问题描述】:

我正在寻找可以将对象数组(对象是类而不是结构)添加到现有数组中的有效算法。要求是如果现有数组包含具有相同id 的对象,该函数将更新该对象(根据更新的对象更改现有对象的属性)。如果object.id 不包含在现有数组中,该函数将简单地将该对象添加到现有数组中。返回数组由新对象和更新对象组成。

如果object.id 是新的,基本上只添加对象。如果 object.id 已经包含,它将更新对象的属性

我在下面试试

func addPhotoArray(_ photos: [Photo], addedPhoto: [Photo]) -> [Photo]{
        var resultArray = photos
        let originalIds = photos.map{$0.id}

        for photo in addedPhoto {
            if !originalIds.contains(photo.id) {
                resultArray.append(photo)
            }
        }
        return resultArray
    }

但我缺少更新要求。我该如何解决这个问题?

更新

用索引替换项目是一种选择。但不确定如果只有 1 或 2 个属性发生变化或根本没有变化,它是否有效。我也在考虑使用Set。如何符合hashable,我们可以使用union函数如下

extension Photo {
    static func union (left: [Photo],right: [Photo] ) -> [Photo]{
        return Array(Set(left).union(Set(right)))
    }

    static func ==(lhs: Photo, rhs: Photo) -> Bool {
        return lhs.id == rhs.id
    }
}

【问题讨论】:

  • 为什么不使用以photo.id 为关键字的字典呢?在我看来,它会更好地满足您的目的
  • 关于您的更新,如果您想要使用 Hashable 的解决方案,您应该提出一个新问题,但据我所知,您将拥有一个完全替换对象的解决方案。
  • 谢谢你的意思是使用 Set 我们最终也会替换现有的项目?

标签: ios arrays swift


【解决方案1】:

我选择不使用 id 数组,而是使用 firstIndex 来查找重复的照片(我假设原始数组中的所有照片都是唯一的),如果找到了,我将其替换为新版本

func addPhotoArray(_ photos: [Photo], addedPhoto: [Photo]) -> [Photo]{
    var resultArray = photos

    for photo in addedPhoto {
        if let photoIndex = resultArray.firstIndex(where: { $0.id == photo.id}) {
            resultArray[photoIndex] = photo
        } else {
            resultArray.append(photo)
        }
    }
    return resultArray
}

【讨论】:

  • 谢谢。替换为 index 是一种选择,但想知道如果仅更改 1.2 属性而不更改任何内容是否有效?我还提出了我们如何实施 Set 的问题
  • 是的,但这不是您问题的一部分,所以我不知道该怎么做。您可以使用first(where:) 来获取现有对象而不是索引,然后使用一些自定义合并函数对其进行更新。
  • 假设我有一个合并函数 mutating func updatePhoto(_ photo: Photo, updatedPhoto: Photo)。我们如何在不完全替换的情况下进行更新?
  • 没有自动方法可以做到这一点,您必须逐个属性检查更改并可能更新它。而且我不会将这样的方法作为类方法,因此接口将是 `updatePhoto(_ updatedPhoto: Photo)
  • 感谢我更改了 func 签名,但我们将该函数放在哪里?我们只更改该项目,而不是 resultArray 中的项目
【解决方案2】:

[YourIdType: YourObjectType] 类型的字典是您的解决方案。插入和检索成本为O(1)。在您的情况下,最坏情况的复杂性将是O(n),其中n = addedArray.count

更多关于Dictionary

【讨论】:

  • 你有我们如何实现字典的例子吗?
  • 为您创建了一个示例here。将其粘贴到 Playground 以查看其工作原理。
  • 更新您的答案,几乎不可能阅读 cmets 部分中的代码
  • 我正在尝试阅读您在 Pasterbin 中的建议。但似乎我们最终还是替换了对象而不是更新它?
  • 如你所说,你的对象是引用类型,所以没关系。一般来说,我建议你限制过早的优化。在分析和确定代码的瓶颈之后,需要进行优化。
【解决方案3】:

你可以试试这个:

func addPhotoArray(_ photos: [Photo], addedPhoto: [Photo]) -> [Photo]{
    var resultArray = photos
    for photo in addedPhoto {
        // Search for the object is it already exists
        if let existingPhotoIndex = photos.firstIndex(where: { (tempPhoto) -> Bool in
                return photo.id == tempPhoto.id
            }) {
             resultArray[existingPhotoIndex] = photo // Replace the object 
        }
        else {
            resultArray.append(photo) // Insert new Object
        }
    }
    return resultArray
}

如果需要,您可以进一步改进。

【讨论】:

  • 这包含逻辑错误和编译错误,photos[existingPhotoIndex] = photo
  • 替换选项是否有效?假设我有一个更新函数,比如变异函数 updatePhoto(_ photo: Photo, updatedPhoto: Photo)。我们如何更新而不是替换? (当只有 1.2 个属性改变或根本没有改变时。更新似乎更好?)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-20
  • 1970-01-01
  • 2012-09-23
  • 2020-03-04
  • 2016-02-20
  • 1970-01-01
相关资源
最近更新 更多