集合(Set) - 插入多个元素

48

Set是一组无序且不重复元素的集合,与数组相似。

我想在一个String类型的Set中添加/插入多个元素,但Swift只提供了一个方法用于插入单个元素(该方法仅接受单个Set元素作为参数),而我的元素是字符串(id)集合。

insert(_:)

@discardableResult mutating func insert(_ newMember: Set.Element) -> (inserted: Bool, memberAfterInsert: Set.Element)

我该怎么做?

我的尝试:
我尝试创建一个与insert(_:)方法非常相似的扩展,但它可以接受多个Set元素。它将与对集合进行迭代相同,但不需要在每个地方手动处理它。

extension Set {

    @discardableResult mutating func insert(_ newMembers: [Set.Element]) -> (inserted: Bool, memberAfterInsert: Set.Element) {

        newMembers.forEach { (member) in
            self.insert(member)
        }
    }
}

如果我按预期返回一个元组,那么它应该可以正常工作,但不知道如何在哪里(哪一行)以及如何返回值。

这里是错误消息。

在一个应该返回 '(inserted: Bool, memberAfterInsert: Set.Element)' 的函数中缺少返回

enter image description here

有什么解决方法吗?是否有更好的解决方案/方法来处理此操作?


1
你为什么想要返回元组? - Milan Nosáľ
这是单个Set元素的方法insert(_:)的默认/实际定义。我想创建一个相同的函数,但它应该接受多个Set元素。 - Krunal
但是你想要的行为是什么?在什么情况下会返回 inserted: true?当插入一个值时吗?没有不同行为的“相同函数”。由你决定函数返回什么。当所有值都被插入时呢?你的用例需要什么 formUnion 不能提供的东西?无论如何,正如米兰所指出的那样,如果你想要返回它,你需要实际返回它。 - Rob Napier
4个回答

88

在问题下的评论中指出了这一点,但我想清楚地说明有一个用于完全相同目的的方法:

mutating func formUnion<S>(_ other: S) where Element == S.Element, S : Sequence

用法:

var attendees: Set = ["Alicia", "Bethany", "Diana"]
let visitors = ["Diana", "Marcia", "Nathaniel"]
attendees.formUnion(visitors)
print(attendees)
// Prints "["Diana", "Nathaniel", "Bethany", "Alicia", "Marcia"]"
还有一个不可变的变体,它返回一个包含联合的新实例:
func union<S>(_ other: S) -> Set<Set.Element> where Element == S.Element, S : Sequence

使用方法:

let attendees: Set = ["Alicia", "Bethany", "Diana"]
let visitors = ["Marcia", "Nathaniel"]
let attendeesAndVisitors = attendees.union(visitors)
print(attendeesAndVisitors)
// Prints "["Diana", "Nathaniel", "Bethany", "Alicia", "Marcia"]"

来源: Apple Developer

转化为中文的结果是:

来源: Apple Developer


21

Swift集合并集

[Swift集合操作]

a.union(b) - a ∪ b - 结果集包含来自ab的所有元素

  • union - 不可变的函数
  • unionInPlace(直到Swift v3) => formUnion - 可变的函数

[可变 vs 不可变]

点击这里阅读更多


2
非常感谢!formUnion函数是我的选择) - CFIFok

6
您的insert声明表明该方法返回一个元组:(inserted: Bool, memberAfterInsert: Set.Element),但是该方法没有返回任何内容。
请使用以下代码:
@discardableResult mutating func insert(_ newMembers: [Set.Element]) {

    newMembers.forEach { (member) in
        self.insert(member)
    }
}

更新

我认为最接近的翻译应该是:

extension Set {
    
    @discardableResult mutating func insert(_ newMembers: [Set.Element]) -> [(inserted: Bool, memberAfterInsert: Set.Element)] {
        var returnArray: [(inserted: Bool, memberAfterInsert: Set.Element)] = []
        newMembers.forEach { (member) in
            returnArray.append(self.insert(member))
        }
        return returnArray
    }
}

推理:

插入文档中说:

返回值

如果集合中未包含 newMember,则返回 (true, newMember)。如果已经包含等于 newMember 的元素,则该方法返回 (false, oldMember),其中 oldMember 是等于 newMember 的元素。在某些情况下,可以通过身份比较或其他方式区分 oldMembernewMember

例如,对于集合 {1、2、3},如果您尝试插入 2,则元组将返回 (false,2),因为 2 已经存在。元组的第二项将是集合中的对象,而不是您提供的对象 - 在这里,使用 Ints,它们是无法区分的,因为只有数字 2 等于 2,但根据 Equatable 实现,您可以有两个不同的对象,它们将被评估为相同。在这种情况下,第二个参数可能对我们很重要。

无论如何,我想说的是,因此单个元组对应于您尝试插入的单个 newMember。如果您尝试插入多个新成员,则无法仅使用单个元组描述该插入 - 其中一些新成员可能已经存在,因此第一个参数将为 false,某些其他成员可能会成功插入,因此对于它们,元组的第一个参数将为 true

因此,我认为正确的方法是返回元组数组 [(inserted: Bool, memberAfterInsert: Set.Element)]


很好,谢谢你的回答,但我已经这样做了。我想让它与单个Set元素的实际定义方法insert(_:)非常相似。我想创建一个相同的函数,但它应该接受多个Set元素。 - Krunal

0

我认为你要找的是这个:

extension Set {
    
    mutating func insert(_ elements: Element...) {
        insert(elements)
    }
    
    mutating func insert(_ elements: [Element]) {
        for element in elements {
            insert(element)
        }
    }
}

你问题中的示例违反了一些好的软件编程原则,比如单一职责原则。看起来你的函数试图同时修改当前集合并返回一个新集合,这真的很令人困惑。你为什么要这样做呢?
如果你想从多个集合创建一个新集合,那么可以按照以下方式操作:
extension Set { 

    /// Initializes a set from multiple sets. 
    /// - Parameter sets: An array of sets. 
    init(_ sets: Self...) {
        self = []
        for set in sets {
            for element in set {
                insert(element)
            }
        }
    }
}

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