Oni-zerone
(Andrea Altea)
1
A thing that I use a lot to reduce the computation cycles when working with arrays is define an HashTable as a Dictionary from my array. To do this I usually define an extension of Array in my codebases like this one:
/// returns a dictionary with mapped keys and values based on transformation block.
/// multiple items with duplicated keys will be overridden, only the last processed will be mantained.
///
/// - Parameters:
/// - transformBlock: launched for each Element of the array, returns a couple of Key and Value
/// - Returns: a dictionary with a couple of Key: Value for each Element of the array
func keyMap<Key: Hashable, Value>(transformBlock: (Element) -> (key: Key, value: Value)) -> [Key: Value] {
var dictionary: [Key: Value] = [:]
forEach { element in
let map = transformBlock(element)
dictionary[map.key] = map.value
}
return dictionary
}
Could this one be a valid proposal or I'm just doing something wrong?
AlexST
2
That would be
let list: [Int] = [1, 2, 3, 4]
let d = Dictionary(uniqueKeysWithValues: list.lazy.map { ($0, "\($0)") })
By using Array.lazy we can skip creating a temporary key/value pair array, correct?
7 Likes
Oni-zerone
(Andrea Altea)
3
This could be a viable solution, but i don't know if is better about performances, (don't know how Dictionary(uniqueKeysWithValues: Sequence) works under the hood).
I usually use this to compare multiple arrays of items,
where you need to recreate the same group of items updating some of them:
func updateItems(newItems: [Item]) {
let map = newItems.keyMap(transformBlock: { return (key: $0.id, value: $0) })
self.referenceItems = internalItems.map { map[$0.id] ?? $0 }
}
or define the map of changes from the array A to the same array shuffled,
so you need to know the positions of those items in both the arrays...
struct Change {
var old: Int
var new: Int
}
func changes(newItems: [Item]) -> [Change] {
let map = newItems.enumerated().keyMap { (offset, element) -> (key: Item, value: Int) in
return (key: element, value: offset)
}
var changes: [Change] = []
self.internalItems.enumerated().forEach { (offset, element) in
if let newPosition = map[element], newPosition != offset {
changes.append(Change(old: offset, new: newPosition))
}
}
return changes
}
AlexST
4
Looks like it works pretty much like your own implementation.
Oni-zerone
(Andrea Altea)
5
I've definetly learned something new today,
Thank You
3 Likes
BrentM
(Brent Mifsud)
6
I always just use a reduce to achieve this purpose. I dont know how performant it is compared to any of the above solutions. But this has always been the easiest way.
struct User: Identifiable {
var id: Int
var name: String
}
let users = [User(id: 1, name: "Bob"), User(id: 2, name: "Lina"), User(id: 3, name: "Joe")]
let dictionary: [AnyHashable: User] = users.reduce(into: [:]) { dictionary, user in
dictionary[user.id] = user
}
if let Joe = dictionary[3] {
print("Retrieved Joe")
}
2 Likes