通过引用传递方式更新数组中的元素

5

如何最简单/正确地更新数组中的项?我希望调用者也能得到更新后的数组。

static func updateItem(updatedItem: Item, inout items: [Item]) -> Bool {
        var item = items.filter{ $0.id == updatedItem.id }.first
        if item != nil {
            item = updatedItem
            return true
        }

        return false
    }

我希望来电者能获取更新后的物品(含更新后的物品)。我认为上述代码的问题在于它只更新了局部变量物品。真正更新物品数组中相关条目的最佳方法是什么?

如果没有与相同id的现有项目,您想对updatedItem执行什么操作? - Alexander
2个回答

5

你可以像超人穿上紧身衣一样——一只腿接着一只腿。循环遍历传入的inout数组,并替换任何与id匹配的项:

func updateItem(updatedItem: Item, items: inout [Item]) -> Bool {
    var result = false
    for ix in items.indices {
        if items[ix].id == updatedItem.id {
            items[ix] = updatedItem
            result = true
        }
    }
    return result
}

请注意,这是Swift 3语法,其中inout位于类型之前而不是标签之前。
使用map可以更加"Swfitily"地编写它:
func updateItem(updatedItem: Item, items: inout [Item]) {
    items = items.map {
        $0.id == updatedItem.id ? updatedItem : $0
    }
}

...但最终结果是一样的。


我返回布尔值是因为调用者根据是否找到项目执行一些额外操作。在你的“迅速”方法中,如果未找到项目,我该如何返回false? - Prabhu
我重写了第一种方法以返回一个Bool,并建议您使用它。使用第二种方法没有任何节省——map仍然是一个循环。 - matt

2
您正在变异一个仅为数组实例副本的item(如果Item是值类型,例如structtupleenum),或者是对它的引用(如果Item是引用类型,例如`class). 无论哪种情况,数组都不会受到影响。
您需要找到数组中实例的索引,然后在该索引处改变数组。
func updateItem(updatedItem: Item, inout items: [Item]) -> Bool {
    guard let index = items.index(where: { $0.id == updatedItem.id }) else {
        return false // No matching item found
    }

    items[index] = updatedItem
    return true
}

然而,这一切都有些笨重。最好使用字典,将 id 映射到具有该 id 的实例上。这意味着您将拥有快速、恒定时间的查找,并且会更方便。实现如下:

// Assuming the "id" is an Int
func updateItem(updatedItem: Item, items: inout [Int: Item]) -> Bool {
    return items.updateValue(updatedItem, forKey: updatedItem.id) != nil
}

谢谢,使用字典后,调用代码会是什么样子? - Prabhu
1
同样的,你只需要传入新项目和所有项目的字典。 - Alexander
嗯,它说类型[Item]的值没有成员index。 - Prabhu
@Prabhu 我认为在Swift 2中不存在这样的函数。你可以编写一个扩展来添加它,但是实际上,最好使用Swift 3。 - Alexander
嗯,问题是我们还没有准备好迁移到Swift 3,所以我想我们只能做扩展了。 - Prabhu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接