How to get count of NSCountedSet? - swift

I'm trying to get count of values from NSCountedSet using loop and have no idea how to get these.
for item in set {
}
I'll be grateful for any help!

You would call count(for:) on the set:
import Foundation
let set: NSCountedSet = ["a", "b", "b", "c", "c", "c"]
for item in set {
print("\(set.count(for: item)) x \"\(item)\"")
}
Prints:
1 x "a"
2 x "b"
3 x "c"

Use method count(for:)
let mySet = NSCountedSet()
mySet.add(1)
mySet.add(2)
mySet.add(2)
for value in mySet {
let count = mySet.count(for: value)
print("Count for \(value) is \(count)")
}
However, note that NSCountedSet is untyped (it's an old Objective-C class), therefore it is not very well suited for Swift.
Luckily, we can implement the same using a simple [T: Int] dictionary.
For example:
struct MyCountedSet<T: Hashable>: Sequence {
typealias Element = T
private var counts: [T: Int] = [:]
mutating func add(_ value: T) {
counts[value, default: 0] += 1
}
func count(for value: T) -> Int {
return counts[value, default: 0]
}
func makeIterator() -> AnyIterator<T> {
return AnyIterator<T>(counts.keys.makeIterator())
}
}
var myCountedSet = MyCountedSet<Int>()
myCountedSet.add(1)
myCountedSet.add(2)
myCountedSet.add(2)
for value in myCountedSet {
let count = myCountedSet.count(for: value)
print("Count for \(value) is \(count)")
}

Related

Is there a high-order function to convert a linked list to an array?

Imagine I have a simple linked list:
class Node {
var parent: Node?
}
// Create the chain: a <- b <- c
let a = Node()
let b = Node(parent: a)
let c = Node(parent: b)
Now I want to convert c into an array ([c, b, a]) so I can use other high-order functions like map.
What is a method that produces an array from a linked list typically called?
Is there a way to use other high-order functions to implement this and not use a loop?
The only implementation I could think of falls back to using a loop:
func chain<T>(_ initial: T, _ next: (T) -> T?) -> [T] {
var result = [initial]
while let n = next(result.last!) {
result.append(n)
}
return result
}
chain(c) { $0.parent } // == [c, b, a]
I'm wondering if there is a built-in way to use functions like map/reduce/etc. to get the same results.
You can use sequence(first:next:) to make a Sequence and then Array() to turn that sequence into an array:
let result = Array(sequence(first: c, next: { $0.parent }))
or equivalently:
let result = Array(sequence(first: c, next: \.parent))
You could use it to implement chain:
func chain<T>(_ initial: T, _ next: #escaping (T) -> T?) -> [T] {
Array(sequence(first: initial, next: next))
}
But I'd just use it directly.
Note: If you just want to call map, you don't need to turn the sequence into an Array. You can just apply .map to the sequence.
For example, here is a useless map that represents each node in the linked list with a 1:
let result = sequence(first: c, next: \.parent).map { _ in 1 }
You could make Node be a "denaturated" sequence, this will automatically bring all high-order functions: map, filter, reduce, flatMap, etc.
class Node {
var parent: Node?
var value: String
init(parent: Node? = nil, value: String = "") {
self.parent = parent
self.value = value
}
}
extension Node: Sequence {
struct NodeIterator: IteratorProtocol {
var node: Node?
mutating func next() -> Node? {
let result = node
node = node?.parent
return result
}
}
func makeIterator() -> NodeIterator {
NodeIterator(node: self)
}
}
// Create the chain: a <- b <- c
let a = Node(value: "a")
let b = Node(parent: a, value: "b")
let c = Node(parent: b, value: "c")
// each node behaves like its own sequence
print(c.map { $0.value }) // ["c", "b", "a"]
print(b.map { $0.value }) // ["b", "a"]

Swift: Lazily encapsulating chains of map, filter, flatMap

I have a list of animals:
let animals = ["bear", "dog", "cat"]
And some ways to transform that list:
typealias Transform = (String) -> [String]
let containsA: Transform = { $0.contains("a") ? [$0] : [] }
let plural: Transform = { [$0 + "s"] }
let double: Transform = { [$0, $0] }
As a slight aside, these are analogous to filter (outputs 0 or 1 element), map (exactly 1 element) and flatmap (more than 1 element) respectively but defined in a uniform way so that they can be handled consistently.
I want to create a lazy iterator which applies an array of these transforms to the list of animals:
extension Array where Element == String {
func transform(_ transforms: [Transform]) -> AnySequence<String> {
return AnySequence<String> { () -> AnyIterator<String> in
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])
.makeIterator()
return AnyIterator {
return iterator.next()
}
}
}
}
which means I can lazily do:
let transformed = animals.transform([containsA, plural, double])
and to check the result:
print(Array(transformed))
I'm pleased with how succinct this is but clearly:
.flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])
is an issue as it means the transform function will only work with an array of 3 transforms.
Edit:
I tried:
var lazyCollection = self.lazy
for transform in transforms {
lazyCollection = lazyCollection.flatMap(transform) //Error
}
var iterator = lazyCollection.makeIterator()
but on the marked row I get error:
Cannot assign value of type 'LazyCollection< FlattenCollection< LazyMapCollection< Array< String>, [String]>>>' to type 'LazyCollection< Array< String>>'
which I understand because each time around the loop another flatmap is being added, so the type is changing.
How can I make the transform function work with an array of any number of transforms?
One WET solution for a limited number of transforms would be (but YUK!)
switch transforms.count {
case 1:
var iterator = self
.lazy
.flatMap(transforms[0])
.makeIterator()
return AnyIterator {
return iterator.next()
}
case 2:
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.makeIterator()
return AnyIterator {
return iterator.next()
}
case 3:
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])
.makeIterator()
return AnyIterator {
return iterator.next()
}
default:
fatalError(" Too many transforms!")
}
Whole code:
let animals = ["bear", "dog", "cat"]
typealias Transform = (String) -> [String]
let containsA: Transform = { $0.contains("a") ? [$0] : [] }
let plural: Transform = { [$0 + "s"] }
let double: Transform = { [$0, $0] }
extension Array where Element == String {
func transform(_ transforms: [Transform]) -> AnySequence<String> {
return AnySequence<String> { () -> AnyIterator<String> in
var iterator = self
.lazy
.flatMap(transforms[0])
.flatMap(transforms[1])
.flatMap(transforms[2])
.makeIterator()
return AnyIterator {
return iterator.next()
}
}
}
}
let transformed = animals.transform([containsA, plural, double])
print(Array(transformed))
You can apply the transformations recursively if you define the method on the Sequence protocol (instead of Array). Also the constraint where Element == String is not needed if the transformations parameter is defined as an array of (Element) -> [Element].
extension Sequence {
func transform(_ transforms: [(Element) -> [Element]]) -> AnySequence<Element> {
if transforms.isEmpty {
return AnySequence(self)
} else {
return lazy.flatMap(transforms[0]).transform(Array(transforms[1...]))
}
}
}
Another approach to achieve what you want:
Edit: I tried:
var lazyCollection = self.lazy
for transform in transforms {
lazyCollection = lazyCollection.flatMap(transform) //Error
}
var iterator = lazyCollection.makeIterator()
You were very near to your goal, if the both types in the Error line was assignable, your code would have worked.
A little modification:
var lazySequence = AnySequence(self.lazy)
for transform in transforms {
lazySequence = AnySequence(lazySequence.flatMap(transform))
}
var iterator = lazySequence.makeIterator()
Or you can use reduce here:
var transformedSequence = transforms.reduce(AnySequence(self.lazy)) {sequence, transform in
AnySequence(sequence.flatMap(transform))
}
var iterator = transformedSequence.makeIterator()
Whole code would be:
(EDIT Modified to include the suggestions from Martin R.)
let animals = ["bear", "dog", "cat"]
typealias Transform<Element> = (Element) -> [Element]
let containsA: Transform<String> = { $0.contains("a") ? [$0] : [] }
let plural: Transform<String> = { [$0 + "s"] }
let double: Transform<String> = { [$0, $0] }
extension Sequence {
func transform(_ transforms: [Transform<Element>]) -> AnySequence<Element> {
return transforms.reduce(AnySequence(self)) {sequence, transform in
AnySequence(sequence.lazy.flatMap(transform))
}
}
}
let transformed = animals.transform([containsA, plural, double])
print(Array(transformed))
How about fully taking this into the functional world? For example using (dynamic) chains of function calls, like filter(containsA) | map(plural) | flatMap(double).
With a little bit of reusable generic code we can achieve some nice stuff.
Let's start with promoting some sequence and lazy sequence operations to free functions:
func lazy<S: Sequence>(_ arr: S) -> LazySequence<S> {
return arr.lazy
}
func filter<S: Sequence>(_ isIncluded: #escaping (S.Element) throws -> Bool) -> (S) throws -> [S.Element] {
return { try $0.filter(isIncluded) }
}
func filter<L: LazySequenceProtocol>(_ isIncluded: #escaping (L.Elements.Element) -> Bool) -> (L) -> LazyFilterSequence<L.Elements> {
return { $0.filter(isIncluded) }
}
func map<S: Sequence, T>(_ transform: #escaping (S.Element) throws -> T) -> (S) throws -> [T] {
return { try $0.map(transform) }
}
func map<L: LazySequenceProtocol, T>(_ transform: #escaping (L.Elements.Element) -> T) -> (L) -> LazyMapSequence<L.Elements, T> {
return { $0.map(transform) }
}
func flatMap<S: Sequence, T: Sequence>(_ transform: #escaping (S.Element) throws -> T) -> (S) throws -> [T.Element] {
return { try $0.flatMap(transform) }
}
func flatMap<L: LazySequenceProtocol, S: Sequence>(_ transform: #escaping (L.Elements.Element) -> S) -> (L) -> LazySequence<FlattenSequence<LazyMapSequence<L.Elements, S>>> {
return { $0.flatMap(transform) }
}
Note that the lazy sequences counterparts are more verbose that the regular Sequence ones, but this is due to the verbosity of LazySequenceProtocol methods.
With the above we can create generic functions that receive arrays and return arrays, and this type of functions are extremely fitted for pipelining, so let's define a pipeline operator:
func |<T, U>(_ arg: T, _ f: (T) -> U) -> U {
return f(arg)
}
Now all we need is to feed something to these functions, but to achieve this we'll need a little bit of tweaking over the Transform type:
typealias Transform<T, U> = (T) -> U
let containsA: Transform<String, Bool> = { $0.contains("a") }
let plural: Transform<String, String> = { $0 + "s" }
let double: Transform<String, [String]> = { [$0, $0] }
With all the above in place, things get easy and clear:
let animals = ["bear", "dog", "cat"]
let newAnimals = lazy(animals) | filter(containsA) | map(plural) | flatMap(double)
print(Array(newAnimals)) // ["bears", "bears", "cats", "cats"]

Limit the size of dictionary in swift

I have a dictionary like this:
static var answer = [String: String]()
How can I limit the number of items to a specific number?
This is a simple way:
var answer = [String: String]()
let limit = 3
func addToDictionary(key: String, value: String) {
let keys = answer.keys
if keys.count < limit || keys.contains(key) {
answer[key] = value
}
}
addToDictionary(key: "uno", value: "one")
addToDictionary(key: "dos", value: "two")
addToDictionary(key: "tres", value: "three")
addToDictionary(key: "quatro", value: "four")
addToDictionary(key: "tres", value: "trois")
print(answer) //["uno": "one", "tres": "trois", "dos": "two"]
This won't prevent adding directly to the dictionary via answer["cinco"] = "five". The proper way would be to create a struct that has the limit property. Here is an example implementation:
struct LimitedDictionary<T: Hashable, U> {
private let limit: UInt
private var dictionary = [T: U]()
init(limit: UInt) {
self.limit = limit
}
subscript(key: T) -> U? {
get {
return dictionary[key]
}
set {
let keys = dictionary.keys
if keys.count < limit || keys.contains(key) {
dictionary[key] = newValue
}
}
}
func getDictionary() -> [T: U] {
return dictionary
}
}
Usage
var dict = LimitedDictionary<String, String>(limit: 3)
dict["uno"] = "one"
dict["dos"] = "two"
dict["tres"] = "three"
dict["quatro"] = "four"
dict["tres"] = "trois"
dict["uno"] //"one"
dict.getDictionary() //["dos": "two", "tres": "trois", "uno": "one"]

Swift Generics, Constraints, and KeyPaths

I'm aware of the limitations of generics in Swift and why they exist so this is not a question about compiler errors. Rather, I occasionally run into situations that seem as though they should be possible with some combination of the resources available in (i.e. generics, associatedTypes/protocols, etc) but can't seem to work out a solution.
In this example, I'm trying to come up with a Swift replacement for NSSortDescriptor (just for fun). It works perfect when you only have one descriptor but, as is often done with the NS version, it would be nice to create an array of SortDescriptors to sort on multiple keys.
The other trial here is using Swift KeyPaths. Because those require a Value type and the comparison requires a Comparable value, I'm running into trouble figuring out where/how to define the types to satisfy everything.
Is this possible? Here is one of the closest solutions I've come up with, but, as you can see at the bottom, it falls short when building an array.
Again, I understand why this doesn't work as is, but am curious if there is a way to achieve the desired functionality.
struct Person {
let name : String
let age : Int
}
struct SortDescriptor<T, V:Comparable> {
let keyPath: KeyPath<T,V>
let ascending : Bool
init(_ keyPath: KeyPath<T,V>, ascending:Bool = true) {
self.keyPath = keyPath
self.ascending = ascending
}
func compare(obj:T, other:T) -> Bool {
let v1 = obj[keyPath: keyPath]
let v2 = other[keyPath: keyPath]
return ascending ? v1 < v2 : v2 < v1
}
}
let jim = Person(name: "Jim", age: 30)
let bob = Person(name: "Bob", age: 35)
let older = SortDescriptor(\Person.age).compare(obj: jim, other: bob) // true
// Heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional
var descriptors = [SortDescriptor(\Person.age), SortDescriptor(\Person.name)]
The problem here is that SortDescriptor is generic on both T and V, but you only want it to be generic on T. That is, you want a SortDescriptor<Person>, because you care that it compares Person. You don't want a SortDescriptor<Person, String>, because once it's created, you don't care that it's comparing on some String property of Person.
Probably the easiest way to “hide” the V is by using a closure to wrap the key path:
struct SortDescriptor<T> {
var ascending: Bool
var primitiveCompare: (T, T) -> Bool
init<V: Comparable>(keyPath: KeyPath<T, V>, ascending: Bool = true) {
primitiveCompare = { $0[keyPath: keyPath] < $1[keyPath: keyPath] }
self.ascending = ascending
}
func compare(_ a: T, _ b: T) -> Bool {
return ascending ? primitiveCompare(a, b) : primitiveCompare(b, a)
}
}
var descriptors = [SortDescriptor(keyPath: \Person.name), SortDescriptor(keyPath: \.age)]
// Inferred type: [SortDescriptor<Person>]
After that, you may want a convenient way to use a sequence of SortDescriptor to compare to objects. For that, we'll need a protocol:
protocol Comparer {
associatedtype Compared
func compare(_ a: Compared, _ b: Compared) -> Bool
}
extension SortDescriptor: Comparer { }
And then we can extend Sequence with a compare method:
extension Sequence where Element: Comparer {
func compare(_ a: Element.Compared, _ b: Element.Compared) -> Bool {
for comparer in self {
if comparer.compare(a, b) { return true }
if comparer.compare(b, a) { return false }
}
return false
}
}
descriptors.compare(jim, bob)
// false
If you're using a newer version of Swift with conditional conformances, you should be able to conditionally conform Sequence to Comparer by changing the first line of the extension to this:
extension Sequence: Comparer where Element: Comparer {
Expanding on #Rob Mayoff's answer, here's a full sorting solution
enum SortDescriptorComparison {
case equal
case greaterThan
case lessThan
}
struct SortDescriptor<T> {
private let compare: (T, T) -> SortDescriptorComparison
let ascending : Bool
init<V: Comparable>(_ keyPath: KeyPath<T,V>, ascending:Bool = true) {
self.compare = {
let v1 = $0[keyPath: keyPath]
let v2 = $1[keyPath: keyPath]
if v1 == v2 {
return .equal
} else if v1 > v2 {
return .greaterThan
} else {
return .lessThan
}
}
self.ascending = ascending
}
func compare(v1:T, v2:T) -> SortDescriptorComparison {
return compare(v1, v2)
}
}
extension Array {
mutating func sort(sortDescriptor: SortDescriptor<Element>) {
self.sort(sortDescriptors: [sortDescriptor])
}
mutating func sort(sortDescriptors: [SortDescriptor<Element>]) {
self.sort() {
for sortDescriptor in sortDescriptors {
switch sortDescriptor.compare(v1: $0, v2: $1) {
case .equal:
break
case .greaterThan:
return !sortDescriptor.ascending
case .lessThan:
return sortDescriptor.ascending
}
}
return false
}
}
}
extension Sequence {
func sorted(sortDescriptor: SortDescriptor<Element>) -> [Element] {
return self.sorted(sortDescriptors: [sortDescriptor])
}
func sorted(sortDescriptors: [SortDescriptor<Element>]) -> [Element] {
return self.sorted() {
for sortDescriptor in sortDescriptors {
switch sortDescriptor.compare(v1: $0, v2: $1) {
case .equal:
break
case .greaterThan:
return !sortDescriptor.ascending
case .lessThan:
return sortDescriptor.ascending
}
}
return false
}
}
}
struct Person {
let name : String
let age : Int
}
let jim = Person(name: "Jim", age: 25)
let bob = Person(name: "Bob", age: 30)
let tim = Person(name: "Tim", age: 25)
let abe = Person(name: "Abe", age: 20)
let people = [tim, jim, bob, abe]
let sorted = people.sorted(sortDescriptors: [SortDescriptor(\Person.age), SortDescriptor(\Person.name)])
print(sorted) //Abe, Jim, Time, Bob
Here's an almost purely functional solution:
// let's add some semantics
typealias SortDescriptor<T> = (T, T) -> Bool
// type constructor for SortDescriptor
func sortDescriptor<T, U: Comparable>(keyPath: KeyPath<T, U>, ascending: Bool) -> SortDescriptor<T> {
return { ascending == ($0[keyPath: keyPath] < $1[keyPath: keyPath]) }
}
// returns a function that can sort any two element of type T, based on
// the provided list of descriptors
func compare<T>(with descriptors: [SortDescriptor<T>]) -> (T, T) -> Bool {
func innerCompare(descriptors: ArraySlice<SortDescriptor<T>>, a: T, b: T) -> Bool {
guard let descriptor = descriptors.first else { return false }
if descriptor(a, b) { return true }
else if descriptor(b, a) { return false }
else { return innerCompare(descriptors: descriptors.dropFirst(1), a: a, b: b) }
}
return { a, b in innerCompare(descriptors: descriptors[0...], a: a, b: b) }
}
// back to imperative, extend Sequence to allow sorting with descriptors
extension Sequence {
func sorted(by descriptors: [SortDescriptor<Element>]) -> [Element] {
return sorted(by: compare(with: descriptors))
}
}
It's based on small, reusable functions, like compare(), that can be easily reused in other scopes.
Usage example:
struct Person {
let name : String
let age : Int
}
let jim = Person(name: "Jim", age: 30)
let bob = Person(name: "Bob", age: 35)
let alice = Person(name: "Alice", age: 35)
let aly = Person(name: "Aly", age: 32)
let descriptors = [sortDescriptor(keyPath: \Person.age, ascending: false),
sortDescriptor(keyPath: \Person.name, ascending: true)]
let persons = [jim, bob, alice, aly]
print(persons.sorted(by: descriptors))

What's the cleanest way of applying map() to a dictionary in Swift?

I'd like to map a function on all keys in the dictionary. I was hoping something like the following would work, but filter cannot be applied to dictionary directly. What's the cleanest way of achieving this?
In this example, I'm trying to increment each value by 1. However this is incidental for the example - the main purpose is to figure out how to apply map() to a dictionary.
var d = ["foo" : 1, "bar" : 2]
d.map() {
$0.1 += 1
}
Swift 4+
Good news! Swift 4 includes a mapValues(_:) method which constructs a copy of a dictionary with the same keys, but different values. It also includes a filter(_:) overload which returns a Dictionary, and init(uniqueKeysWithValues:) and init(_:uniquingKeysWith:) initializers to create a Dictionary from an arbitrary sequence of tuples. That means that, if you want to change both the keys and values, you can say something like:
let newDict = Dictionary(uniqueKeysWithValues:
oldDict.map { key, value in (key.uppercased(), value.lowercased()) })
There are also new APIs for merging dictionaries together, substituting a default value for missing elements, grouping values (converting a collection into a dictionary of arrays, keyed by the result of mapping the collection over some function), and more.
During discussion of the proposal, SE-0165, that introduced these features, I brought up this Stack Overflow answer several times, and I think the sheer number of upvotes helped demonstrate the demand. So thanks for your help making Swift better!
With Swift 5, you can use one of the five following snippets in order to solve your problem.
#1. Using Dictionary mapValues(_:) method
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let newDictionary = dictionary.mapValues { value in
return value + 1
}
//let newDictionary = dictionary.mapValues { $0 + 1 } // also works
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
#2. Using Dictionary map method and init(uniqueKeysWithValues:) initializer
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let tupleArray = dictionary.map { (key: String, value: Int) in
return (key, value + 1)
}
//let tupleArray = dictionary.map { ($0, $1 + 1) } // also works
let newDictionary = Dictionary(uniqueKeysWithValues: tupleArray)
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
#3. Using Dictionary reduce(_:_:) method or reduce(into:_:) method
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let newDictionary = dictionary.reduce([:]) { (partialResult: [String: Int], tuple: (key: String, value: Int)) in
var result = partialResult
result[tuple.key] = tuple.value + 1
return result
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let newDictionary = dictionary.reduce(into: [:]) { (result: inout [String: Int], tuple: (key: String, value: Int)) in
result[tuple.key] = tuple.value + 1
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
#4. Using Dictionary subscript(_:default:) subscript
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
var newDictionary = [String: Int]()
for (key, value) in dictionary {
newDictionary[key, default: value] += 1
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
#5. Using Dictionary subscript(_:) subscript
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
var newDictionary = [String: Int]()
for (key, value) in dictionary {
newDictionary[key] = value + 1
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
While most of the answers here focus on how to map the entire dictionary (keys and values), the question really only wanted to map the values. This is an important distinction since mapping values allows you to guarantee the same number of entries, whereas mapping both key and value might result in duplicate keys.
Here’s an extension, mapValues, that allows you to map just the values. Note it also extends dictionary with an init from a sequence of key/value pairs, which is a bit more general than initializing it from an array:
extension Dictionary {
init<S: SequenceType where S.Generator.Element == Element>
(_ seq: S) {
self.init()
for (k,v) in seq {
self[k] = v
}
}
func mapValues<T>(transform: Value->T) -> Dictionary<Key,T> {
return Dictionary<Key,T>(zip(self.keys, self.values.map(transform)))
}
}
The cleanest way is to just add map to Dictionary:
extension Dictionary {
mutating func map(transform: (key:KeyType, value:ValueType) -> (newValue:ValueType)) {
for key in self.keys {
var newValue = transform(key: key, value: self[key]!)
self.updateValue(newValue, forKey: key)
}
}
}
Checking that it works:
var dic = ["a": 50, "b": 60, "c": 70]
dic.map { $0.1 + 1 }
println(dic)
dic.map { (key, value) in
if key == "a" {
return value
} else {
return value * 2
}
}
println(dic)
Output:
[c: 71, a: 51, b: 61]
[c: 142, a: 51, b: 122]
You can also use reduce instead of map. reduce is capable of doing anything map can do and more!
let oldDict = ["old1": 1, "old2":2]
let newDict = reduce(oldDict, [String:Int]()) { dict, pair in
var d = dict
d["new\(pair.1)"] = pair.1
return d
}
println(newDict) // ["new1": 1, "new2": 2]
It would be fairly easy to wrap this in an extension, but even without the extension it lets you do what you want with one function call.
Swift 5
map function of dictionary comes with this syntax.
dictData.map(transform: ((key: String, value: String)) throws -> T)
you can just set closure values to this
var dictData: [String: String] = [
"key_1": "test 1",
"key_2": "test 2",
"key_3": "test 3",
"key_4": "test 4",
"key_5": "test 5",
]
dictData.map { (key, value) in
// Operations on values or key
}
It may be give this warning Result of call to 'map' is unused
Then just set _ = before variable.
May be it will help you
Thank you.
It turns out you can do this. What you have to do is create an array from the MapCollectionView<Dictionary<KeyType, ValueType>, KeyType> returned from the dictionaries keys method. (Info here) You can then map this array, and pass the updated values back to the dictionary.
var dictionary = ["foo" : 1, "bar" : 2]
Array(dictionary.keys).map() {
dictionary.updateValue(dictionary[$0]! + 1, forKey: $0)
}
dictionary
I was looking for a way to map a dictionary right into a typed Array with custom objects. Found the solution in this extension:
extension Dictionary {
func mapKeys<U> (transform: Key -> U) -> Array<U> {
var results: Array<U> = []
for k in self.keys {
results.append(transform(k))
}
return results
}
func mapValues<U> (transform: Value -> U) -> Array<U> {
var results: Array<U> = []
for v in self.values {
results.append(transform(v))
}
return results
}
func map<U> (transform: Value -> U) -> Array<U> {
return self.mapValues(transform)
}
func map<U> (transform: (Key, Value) -> U) -> Array<U> {
var results: Array<U> = []
for k in self.keys {
results.append(transform(k as Key, self[ k ]! as Value))
}
return results
}
func map<K: Hashable, V> (transform: (Key, Value) -> (K, V)) -> Dictionary<K, V> {
var results: Dictionary<K, V> = [:]
for k in self.keys {
if let value = self[ k ] {
let (u, w) = transform(k, value)
results.updateValue(w, forKey: u)
}
}
return results
}
}
Using it as followed:
self.values = values.map({ (key:String, value:NSNumber) -> VDLFilterValue in
return VDLFilterValue(name: key, amount: value)
})
Swift 3
I try an easy way in Swift 3.
I want to map [String: String?] to [String : String], I use forEach instead of map or flat map.
let oldDict = ["key0": "val0", "key1": nil, "key1": "val2","key2": nil]
var newDict = [String: String]()
oldDict.forEach { (source: (key: String, value: String?)) in
if let value = source.value{
newDict[source.key] = value
}
}
According to the Swift Standard Library Reference, map is a function of arrays. Not for dictionaries.
But you could iterate your dictionary to modify the keys:
var d = ["foo" : 1, "bar" : 2]
for (name, key) in d {
d[name] = d[name]! + 1
}
I you're only trying to map the values (potentially changing their type), include this extension:
extension Dictionary {
func valuesMapped<T>(_ transform: (Value) -> T) -> [Key: T] {
var newDict = [Key: T]()
for (key, value) in self {
newDict[key] = transform(value)
}
return newDict
}
}
Given you have this dictionary:
let intsDict = ["One": 1, "Two": 2, "Three": 3]
Single-line value transformation then looks like this:
let stringsDict = intsDict.valuesMapped { String($0 * 2) }
// => ["One": "2", "Three": "6", "Two": "4"]
Multi-line value transformation then looks like this:
let complexStringsDict = intsDict.valuesMapped { (value: Int) -> String in
let calculationResult = (value * 3 + 7) % 5
return String("Complex number #\(calculationResult)")
}
// => ["One": "Complex number #0", "Three": ...
Another approach is to map to a dictionary and reduce, where functions keyTransform and valueTransform are functions.
let dictionary = ["a": 1, "b": 2, "c": 3]
func keyTransform(key: String) -> Int {
return Int(key.unicodeScalars.first!.value)
}
func valueTransform(value: Int) -> String {
return String(value)
}
dictionary.map { (key, value) in
[keyTransform(key): valueTransform(value)]
}.reduce([Int:String]()) { memo, element in
var m = memo
for (k, v) in element {
m.updateValue(v, forKey: k)
}
return m
}
Swift 3 I used this,
func mapDict(dict:[String:Any])->[String:String]{
var updatedDict:[String:String] = [:]
for key in dict.keys{
if let value = dict[key]{
updatedDict[key] = String(describing: value)
}
}
return updatedDict
}
Usage:
let dict:[String:Any] = ["MyKey":1]
let mappedDict:[String:String] = mapDict(dict: dict)
Ref
Swift 3
Usage:
let value = ["a": "AAA", "b": "BBB", "c": "CCC"]
value.transformed { ($1, $0) } // ["BBB": "b", "CCC": "c", "AAA": "a"]
Extension:
extension Dictionary {
func transformed(closure: (Key, Value) -> (Key, Value)?) -> [Key: Value] {
var dict = [Key: Value]()
for key in keys {
guard
let value = self[key],
let keyValue = closure(key, value)
else { continue }
dict[keyValue.0] = keyValue.1
}
return dict
}
}