Swift에서 설정할 배열 줄이기


80

객체 배열을 Swift에서 세트로 줄이려고하는데 이것이 내 코드입니다.

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

그러나 오류가 발생합니다.

Type of expression is ambiguous without more context.

URL 유형이 확실히 String이기 때문에 문제가 무엇인지 이해하지 못합니다. 어떤 아이디어?


나는 reduce의 서명 func reduce<T>(_ initial: T, @noescape combine combine: (T, Self.Generator.Element) throws -> T) rethrows -> T이 당신이 전달하는 것이 아니라고 생각합니다.
Martin Marconcini 2015

답변:


138

집합으로 만들기 위해 배열을 줄일 필요가 없습니다. 배열로 세트를 만듭니다 let objectSet = Set(objects.map { $0.URL })..


그러나 나는 객체 세트가 아니라 이러한 객체가 가진 다른 URL 세트를 원합니다. 나는지도를 할 수 있고 Set (map) 할 수 있다고 생각하지만, 이것을 줄이면 이것을 달성 할 수 있어야합니다.
바나나

1
아. 그런 다음 let objectSet = Set(objects.map { $0.URL }).
NRitH 2015

아, 좋아요. 내가 받아 들일 수 있도록 대답을 편집 해 주시겠습니까?
바나나

때에 따라 다르지. 매핑 / 플랫 맵하면 체인 호출에 좋습니다.
Ben Affleck

17

Swift 5.1에서는 문제를 해결하기 위해 다음 세 가지 예제 중 하나를 사용할 수 있습니다.


#1. 사용 Arraymap(_:)방법 Setinit(_:)초기화를

가장 간단한 경우에는 초기 배열을 urls ( String) 배열에 매핑 한 다음 해당 배열에서 집합을 만들 수 있습니다. 아래 코드는 그 방법을 보여줍니다.

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"

#삼. Array확장 사용

필요한 경우, 당신은 만들 수 있습니다 mapToSet에 대한 방법 Array소요 transform폐쇄 매개 변수를과를 반환합니다 Set. 코드 아래의 플레이 그라운드는 사용 방법을 보여줍니다.

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"

5

reduce()method는 결합 된 값 을 반환 하는 클로저를 기대 하지만 value의 insert()메서드는 Set아무것도 반환하지 않고 대신 기존 세트에 새 요소를 삽입합니다.

작동하게하려면 다음과 같은 작업을 수행해야합니다.

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

그러나 위의 내용은 약간의 불필요한 복잡성입니다. 큰 배열이 있다면 Swift가 objects. @NRitH의 조언을 따르고 map()한 번에 결과 세트를 만들 수 있으므로 사용하십시오 .


이 답변에 감사 드리며 문제를 명확히 설명합니다.
바나나

@ 바나나, np. 내 편집 된 답변을 참조하십시오. 그것은 지나치게 복잡 할뿐만 아니라 비효율적 인 일이기도합니다.
courteouselk

이것은 정말 나쁜 해결책입니다. 새 집합 인스턴스를 만들 때마다. developer.apple.com/documentation/swift/set/3128858-union . Union 새로운 세트를 반환합니다.
Vyacheslav

1

경우 URL개체에 대한 강력한 형식의이 String새 만들 수 있습니다 Set<String>개체 및 사용에 unionInPlace매핑 된 배열로 세트를 :

var mySet = Set<String>()
mySet.unionInPlace(objects.map { $0.URL as String })
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.