Swift 4.2
我有多个函数可以替换数组中的对象或结构(如果存在),如果不存在,则将其添加。
func updateFruit(_ fruit: Fruit)
{
if let idx = fruitArray.firstIndex(where: { $0.id == fruit.id })
{
fruitArray[idx] = fruit
}
else
{
fruitArray.append(fruit)
}
}
很明显,我可以将其扩展为Array:
extension Array
{
mutating func replaceOrAppend(_ item: Element, whereFirstIndex predicate: (Element) -> Bool)
{
if let idx = self.firstIndex(where: predicate)
{
self[idx] = item
}
else
{
append(item)
}
}
}
但是,有没有更简单,更轻松的方式来表达这一点?最好使用闭包或内置函数。
注意:当前实现不允许使用集合。
答案 0 :(得分:1)
考虑到您经常检查$0.<prop> == newthing.<prop>
的用例,您可以通过添加以下内容来进一步提高这一点:
mutating func replaceOrAppend<Value>(_ item: Element,
firstMatchingKeyPath keyPath: KeyPath<Element, Value>)
where Value: Equatable
{
let itemValue = item[keyPath: keyPath]
replaceOrAppend(item, whereFirstIndex: { $0[keyPath: keyPath] == itemValue })
}
然后您可以像这样使用它:
struct Student {
let id: Int
let name: String
}
let alice0 = Student(id: 0, name: "alice")
let alice1 = Student(id: 1, name: "alice")
let bob = Student(id: 0, name: "bob")
var array = [alice0]
array.replaceOrAppend(alice1, firstMatchingKeyPath: \.name) // [alice1]
array.replaceOrAppend(bob, firstMatchingKeyPath: \.name) // [alice1, bob]
当然,如果您经常执行此操作,则可以继续抬起头来。
protocol Identifiable {
var id: Int { get }
}
extension Student: Identifiable {}
extension Array where Element: Identifiable {
mutating func replaceOrAppendFirstMatchingID(_ item: Element)
{
replaceOrAppend(item, firstMatchingKeyPath: \.id)
}
}
array.replaceOrAppendFirstMatchingID(alice0) // [alice1, alice0]
答案 1 :(得分:0)
我建议使用protocol
创建Replacable
replaceValue
,它将代表我们可以用来枚举对象的标识符。
protocol Replacable {
var replaceValue: Int { get }
}
现在我们可以创建Array
的扩展名,但是现在我们可以从这样的示例代码中删除谓词
extension Array where Element: Replacable {
mutating func replaceOrAppend(_ item: Element) {
if let idx = self.firstIndex(where: { $0.replaceValue == item.replaceValue }) {
self[idx] = item
}
else {
append(item)
}
}
}
由于Set
不是有序集合,因此如果集合包含对象,我们可以简单地删除它并插入新值
extension Set where Element: Replacable {
mutating func replaceOrAppend(_ item: Element) {
if let existItem = self.first(where: { $0.replaceValue == item.replaceValue }) {
self.remove(existItem)
}
self.insert(item)
}
}
答案 2 :(得分:0)
假设您的类型是相等的,这是一个通用扩展名:
extension RangeReplaceableCollection where Element: Equatable {
mutating func addOrReplace(_ element: Element) {
if let index = self.firstIndex(of: element) {
self.replaceSubrange(index...index, with: [element])
}
else {
self.append(element)
}
}
}
尽管如此,请记住,我(和您)的功能只会替换一个匹配项。
全面工作场所测试: