减少数组以在 Swift 中设置

Posted

技术标签:

【中文标题】减少数组以在 Swift 中设置【英文标题】:Reduce array to set in Swift 【发布时间】:2016-03-13 17:18:36 【问题描述】:

我试图在 Swift 中将对象数组简化为一个集合,这是我的代码:

objects.reduce(Set<String>())  $0.insert($1.URL) 

但是,我收到一个错误:

Type of expression is ambiguous without more context.

我不明白问题出在哪里,因为 URL 的类型肯定是字符串。有什么想法吗?

【问题讨论】:

我认为reduce的签名是func reduce&lt;T&gt;(_ initial: T, @noescape combine combine: (T, Self.Generator.Element) throws -&gt; T) rethrows -&gt; T,这不是你要传递的。 【参考方案1】:

你不必减少一个数组来把它变成一个集合;只需使用数组创建集合:let objectSet = Set(objects.map $0.URL )

【讨论】:

但是我不想要对象集,而是这些对象拥有的不同 URL 集。我想我可以先做一个 map 然后 Set(map),但我应该可以用 reduce 来实现。 啊。然后let objectSet = Set(objects.map $0.URL ). 啊,好的,太好了。您能否编辑您的答案以便我接受? 视情况而定。如果您使用 map/flatmap,它可以很好地链接调用。【参考方案2】:

reduce() 方法需要一个返回组合值的闭包,而Set 值的insert() 方法不返回任何内容,而是在现有集合中插入一个新元素。

为了使其正常工作,您需要执行以下操作:

objects.reduce(Set<String>()) 
    $0.union(CollectionOfOne($1.URL))

但以上内容有点不必要的复杂化。如果你有一个大数组,这意味着在 Swift 遍历 objects 中的所有元素时,要创建相当多的不断增长的集合。最好遵循@NRitH 的建议并使用map(),因为这样可以一次性完成结果集。

【讨论】:

感谢您的回答,它为我澄清了问题。 @Banana,NP。请参阅我编辑的答案。事实证明,这不仅过于复杂,而且效率低下。 这是一个非常糟糕的解决方案。每次您创建一个新的集合实例。 developer.apple.com/documentation/swift/set/3128858-union 。 Union 返回一个新集合。【参考方案3】:

仅适用于 Swift 1.0-2.x:

如果您的对象上的URL 是强类型String,您可以创建一个新的Set&lt;String&gt; 对象并使用映射数组的集合上的unionInPlace

var mySet = Set<String>()
mySet.unionInPlace(objects.map  $0.URL as String )

【讨论】:

这应该是formUnionunionInPlace 不是 Swift 的一部分 嘿@Drew,这个答案写于 2015 年 12 月,当时unionInPlace 是 Swift 2 的一部分。【参考方案4】:

使用 Swift 5.1,您可以使用以下三个示例之一来解决您的问题。


#1。使用Arraymap(_:)方法和Setinit(_:)初始化器

在最简单的情况下,您可以将初始数组映射到 urls (String) 的数组,然后从该数组创建一个集合。下面的 Playground 代码展示了如何做到这一点:

struct MyObject 
    let url: String


let objectArray = [
    MyObject(url: "mozilla.org"),
    MyObject(url: "gnu.org"),
    MyObject(url: "git-scm.com")
]

let urlArray = objectArray.map( $0.url )
let urlSet = Set(urlArray)
dump(urlSet)
// ▿ 3 members
//   - "git-scm.com"
//   - "mozilla.org"
//   - "gnu.org"

#2。使用Arrayreduce(into:_:)方法

struct MyObject 
    let url: String


let objectArray = [
    MyObject(url: "mozilla.org"),
    MyObject(url: "gnu.org"),
    MyObject(url: "git-scm.com")
]

let urlSet = objectArray.reduce(into: Set<String>(),  (urls, object) in
    urls.insert(object.url)
)
dump(urlSet)
// ▿ 3 members
//   - "git-scm.com"
//   - "mozilla.org"
//   - "gnu.org"

作为替代方案,您可以使用Arrayreduce(_:_:) 方法:

struct MyObject 
    let url: String


let objectArray = [
    MyObject(url: "mozilla.org"),
    MyObject(url: "gnu.org"),
    MyObject(url: "git-scm.com")
]

let urlSet = objectArray.reduce(Set<String>(),  (partialSet, object) in
    var urls = partialSet
    urls.insert(object.url)
    return urls
)
dump(urlSet)
// ▿ 3 members
//   - "git-scm.com"
//   - "mozilla.org"
//   - "gnu.org"

#3。使用Array 扩展

如有必要,您可以为Array 创建一个mapToSet 方法,该方法接受transform 闭包参数并返回Set。下面的 Playground 代码展示了如何使用它:

extension Array 

    func mapToSet<T: Hashable>(_ transform: (Element) -> T) -> Set<T> 
        var result = Set<T>()
        for item in self 
            result.insert(transform(item))
        
        return result
    



struct MyObject 
    let url: String


let objectArray = [
    MyObject(url: "mozilla.org"),
    MyObject(url: "gnu.org"),
    MyObject(url: "git-scm.com")
]

let urlSet = objectArray.mapToSet( $0.url )
dump(urlSet)
// ▿ 3 members
//   - "git-scm.com"
//   - "mozilla.org"
//   - "gnu.org"

【讨论】:

以上是关于减少数组以在 Swift 中设置的主要内容,如果未能解决你的问题,请参考以下文章

在 XML 中设置提示点以在 Flash 视频中使用

如何裁剪或调整图像大小以在 asp.net 中设置纵横比

从数组中设置自定义单元格 uibutton 标题 - Swift

如何在 swift 4 中的 UserDefalts 中设置自定义类数组数据

如何在以下代码中设置条件以在分页中标记当前页面?

如何在 UIImage 数组中设置第二张或中间的图像? (斯威夫特 3)