Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating dictionaries from identifiable values #568

Open
kielgillard opened this issue Apr 29, 2024 · 2 comments
Open

Creating dictionaries from identifiable values #568

kielgillard opened this issue Apr 29, 2024 · 2 comments

Comments

@kielgillard
Copy link

kielgillard commented Apr 29, 2024

I'm considering asking the Swift developer community if they have ever found this very small enhancement as useful as I have found it to be and if they would like to see it pitched. But before I do so, do you, the repository owners, think this is a good idea? Should this go into swift-algorithms first? Anything other thoughts?

I note this example is not the most performant implementation but could be a reason to offer such an initialiser in Foundation.

extension Dictionary where Value: Identifiable {
    
    /// Creates a new dictionary from the `Identifiable` values in the given sequence, keying the values by their identifier, using the `combine` closure to de-duplicate keys.
    init<Values: Sequence>(identifiableValues: Values, uniquingKeysWith combine: (Value, Value) -> Value) where Key == Values.Element.ID, Value == Values.Element {
        let keysAndValues = identifiableValues.map { ($0.id, $0) }
        self.init(keysAndValues, uniquingKeysWith: combine)
    }
    
    /// Creates a new dictionary from the `Identifiable` values in the given sequence, keying the values by their identifier.
    init<Values: Sequence>(uniquelyIdentifiableValues identifiedValues: Values) where Key == Values.Element.ID, Value == Values.Element {
        let uniqueKeysAndValues = identifiedValues.map { ($0.id, $0) }
        self.init(uniqueKeysWithValues: uniqueKeysAndValues)
    }
}

func testExample() throws {
    let people = [
        Person(id: 0, name: "Kiel"),
        Person(id: 1, name: "Erin"),
        Person(id: 2, name: "Amelia"),
        Person(id: 3, name: "James"),
    ]
    
    let dictionary = Dictionary(uniquelyIdentifiableValues: people)
    
    let expectation = [
        people[0].id: people[0],
        people[1].id: people[1],
        people[2].id: people[2],
        people[3].id: people[3],
    ]
    
    XCTAssertEqual(expectation, dictionary)
}
@kielgillard
Copy link
Author

Perhaps a more useful abstraction is this (and again, I note this example is not the most performant implementation but could be a reason to offer such an initialiser in Foundation):

extension Dictionary {
    
    init<Values: Sequence>(values: Values, keyedBy keyGenerator: (Value) -> (Key), uniquingKeysWith combine: (Value, Value) -> Value) where Value == Values.Element {
        let keysAndValues = values.map { (keyGenerator($0), $0) }
        self.init(keysAndValues, uniquingKeysWith: combine)
    }
    
    init<Values: Sequence>(uniquelyKeyableValues: Values, keyedBy keyGenerator: (Value) -> (Key)) where Value == Values.Element {
        let uniqueKeysAndValues = uniquelyKeyableValues.map { (keyGenerator($0), $0) }
        self.init(uniqueKeysWithValues: uniqueKeysAndValues)
    }
}

extension Dictionary where Value: Identifiable {
    
    /// Creates a new dictionary from the `Identifiable` values in the given sequence, keying the values by their identifier, using the `combine` closure to de-duplicate keys.
    init<Values: Sequence>(identifableValues: Values, uniquingKeysWith combine: (Value, Value) -> Value) where Key == Values.Element.ID, Value == Values.Element {
        self.init(values: identifableValues, keyedBy: \.id, uniquingKeysWith: combine)
    }
    
    /// Creates a new dictionary from the `Identifiable` values in the given sequence, keying the values by their identifier.
    init<Values: Sequence>(uniquelyIdentifableValues identifiedValues: Values) where Key == Values.Element.ID, Value == Values.Element {
        self.init(uniquelyKeyableValues: identifiedValues, keyedBy: \.id)
    }
}

@kielgillard
Copy link
Author

Looks like there's already something in swift-algorithms: https://github.com/apple/swift-algorithms/blob/main/Guides/Keyed.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant