Swift中数组的唯一值

106

我正在使用 Swift 构建 iOS 应用程序,需要获取字符串数组的所有唯一值。

我已经阅读了 Apple 开发者文档,但似乎没有相应的函数可用。

有人可以给我一个提示吗?


3
请查阅 NSSet 或 NSOrderedSet。 - rdelmar
我使用Dollar库。$.uniq(array) https://github.com/ankurp/Dollar#uniq---uniq - Andrew
不再需要编写扩展。苹果已经在算法包中提供了uniqued()方法。更多信息请参见https://dev59.com/Q18e5IYBdhLWcg3wdqGT#70210590 - Kaunteya
4个回答

210

可能存在更加高效的方法,但扩展程序可能是最直接的选择:

extension Array where Element: Equatable {
    var unique: [Element] {
        var uniqueValues: [Element] = []
        forEach { item in
            guard !uniqueValues.contains(item) else { return }
            uniqueValues.append(item)
        }
        return uniqueValues
    }
}

如果顺序不重要且对象也可哈希:

let array = ["one", "one", "two", "two", "three", "three"]
// order NOT guaranteed
let unique = Array(Set(array))
// ["three", "one", "two"]

3
第一个示例简单明了,适用于Swift 3。谢谢! - Canucklesandwich
4
Array(Set()) 在 Swift 4 中同样适用。非常好的解决方案。谢谢。 - Anjan Biswas
3
否定。您可以使用set获取随机顺序。 - BB9z
9
我在回答中指出了这一点,并提供了一个保留顺序的扩展,所以不知道你想要什么 :) - Logan
1
第一种变体在大数据集上具有较差的性能特征。请谨慎使用。 - Aliaksandr Bialiauski
显示剩余3条评论

75

Swift标准库中没有这样的函数,但您可以编写一个功能:

extension Sequence where Iterator.Element: Hashable {
    func unique() -> [Iterator.Element] {
        var seen: [Iterator.Element: Bool] = [:]
        return self.filter { seen.updateValue(true, forKey: $0) == nil }
    }
}

let a = ["four","one", "two", "one", "three","four", "four"]
a.unique // ["four", "one", "two", "three"]

这种方法的缺点是需要使序列的内容成为可哈希的,而不仅仅是可比较的,但是大多数可比较的东西都可以被哈希,包括字符串。

与将内容放入字典或集合中再重新获取不同,此方法也可以保留原始顺序。


有错误吗?使用未解决的标识符'seq' - μολὼν.λαβέ
1
啊,原来是这样,应该是 filter(source) - Airspeed Velocity
1
这在Swift 2中会抛出一个错误。应该是source.filter - rob
1
无法在Swift 3中工作。你有什么想法吗? - Bruno
2
Set也可以用于去重 var seen = Set<Element>() return filter { seen.update(with: $0) == nil } - Igor Palaguta
显示剩余3条评论

4

我不知道有内置的方法。这个通用函数可以做到:

func distinct<S: SequenceType, E: Equatable where E==S.Generator.Element>(source: S) -> [E]
{
    var unique = [E]()

    for item in source
    {
        if !contains(unique, item)
        {
            unique.append(item)
        }
    }
    return unique
}

这种解决方案的缺点是其时间复杂度为O(n2)。

"contains" 函数执行时间为 O(n),因此此解决方案运行时间为二次级别(虽然它不需要元素是可散列的,这是它的优点)。 - Airspeed Velocity
@AirspeedVelocity 是的,那是个很好的观点。而且像你在你的解决方案中指出的那样,可哈希性通常不会成为问题。尽管如此,如果必须要是可哈希的,则这是一种备选但较慢的解决方案。我更喜欢你的解决方案,但我认为我会因为这个原因将其保留。 - Ben Kane
重载意味着你可以实现两个方法,最好的方法将被选择!(因为Hashable符合Equatable,所以更具体,重载解析器会优先选择它 :)) - Airspeed Velocity
只要你让这两个版本都采用序列或数组的形式,它们就不会冲突。 - Airspeed Velocity
没错!得爱上Swift :) 我会编辑我的答案,使序列更通用,以防有人想采取重载方法。 - Ben Kane

1

使用类似于var unique = [<yourtype>:Bool]()的字典,并在循环中填入值,例如unique[<array value>] = true。现在unique.keys中包含了你所需要的内容。


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