Is there some short cut form of writing: .map { $0 } - swift

.map { $0 }
I feel like it should be possible to write as just:
.map()
or something
Or real world example:
let values = Dict<String: [Int]>(some data here).values.flatMap { $0 }

Yes you can actually use flatMap and pass value as the keypath:
let dict: [String: [Int]] = ["a": [1,2,3]]
let values = dict.flatMap(\.value) // [1, 2, 3]

Related

How to initialize a case insensitive dictionary using Swift?

My problem is that this code is case-sensitive. If I have "Sam" and "sam", they will be sorted into different keys. Any way that I can think of doing this is by converting the string into all lowercase, but I want it to stay as normal while being sorted without case-sensitivity:
var dict: [String: [String]] = [:]
for string in array {
if (dict[string] != nil) {
dict[string]?.append(string)
}
else {
dict[string] = [string]
}
}
As it is right now my code would result in:
["Sam": ["Sam"], "sam", ["sam"]]
Instead of what I want:
["Sam": ["Sam", "sam"]]
How can I accomplish this?
You can use reduce(into:) method and assign each element capitalized to the result:
let array = ["Sam", "sam", "SAM"]
let dict: [String: [String]] = array.reduce(into: [:]) {
$0[$1.capitalized, default: []].append($1)
}
print(dict) // ["Sam": ["Sam", "sam", "SAM"]]
If you just want to have case insensitive keys and case sensitive values, from given array, the shortest solution could be something like this:
var dict: [String: [String]] = [:]
array.forEach { dict[$0.lowercased(), default: []] += [$0] }

Get all values into dictionary and create a String with a specific format

I have a dictionary with this structure:
a: [1,2]
b: [3,4]
c: [5,6]
and I need to return a string with this structure.
a,b,c\n1,3,5\n2,4,6
I solved the first part of the string. But to get the rest of the String. I try to iterate into my dictionary to get the first elements for each key in my dictionary and then get the rest for each value into the array.
Is there an easier way to get this?
Once you know what's the order of the keys (alpha ?), you can use this:
let dict: [String: [Int]] = ["a": [1,2], "b": [3, 4], "c": [5, 6]]
let keys = dict.keys.sorted() //Or do whatever you want here to get your target order
var matrix: [[String]] = []
keys.forEach {
guard let arrayAsInt = dict[$0] else { return }
let arrayAsString = arrayAsInt.map{ "\($0)" }
matrix.append( [$0] + arrayAsString)
}
print("Matrix: \(matrix)")
let transposed = matrix.transposed()
print("Transposed Matrix: \(transposed)")
let output = transposed.map { $0.joined(separator: ",")}.joined(separator: "\n")
print(output)
The outputs:
$>Matrix: [["a", "1", "2"], ["b", "3", "4"], ["c", "5", "6"]]
$>Transposed Matrix: [["a", "b", "c"], ["1", "3", "5"], ["2", "4", "6"]]
$>a,b,c
1,3,5
2,4,6
Obvisouly the "\n" might be invisible and be an actual new line
a,b,c
1,3,5
2,4,6
Being
a,b,c\n1,3,5\n2,4,6
What's the idea behind that? Create a matrix and use the transpose (it's used in maths with matrix, it's one of the basic modification of a matrix).
First transform the [String: [Int]] into a [[String]], where each element would be key followed by its values. I transformed it there as String for simpler code later.
Why doing that? Because the matrix value is easy to get from your initial dict. the transposed value is harder (not impossible) to get from dict but easier from matrix, and the transposed is quickly transformed into your format.
So my thinking was the reverse:
Get a structure from your output, then how to get it, it's a transpose, so I need to get the initial input as it, etc.
With the help of a code for Transpose Matrix (that accept String elements).
extension Collection where Self.Iterator.Element: RandomAccessCollection {
// PRECONDITION: `self` must be rectangular, i.e. every row has equal size.
func transposed() -> [[Self.Iterator.Element.Iterator.Element]] {
guard let firstRow = self.first else { return [] }
return firstRow.indices.map { index in
self.map{ $0[index] }
}
}
}
Any code (there a various) working ones, should the trick. I took it from here.
As pointed by #Leo Dabus, you can remove the Self.Iterator.Element
from the extension code (twice). I just wanted to it as such, not modifying the initial answer since it's not mind.
What you are looking for, besides composing the final string, is how to transpose a collection (this would work with collections of different sizes as well):
extension Sequence {
func max<T: Comparable>(_ predicate: (Element) -> T) -> Element? {
self.max(by: { predicate($0) < predicate($1) })
}
}
extension Collection where Element: RandomAccessCollection, Element.Indices == Range<Int> {
func transposed() -> [[Element.Element]] {
(0..<(max(\.count)?.count ?? .zero)).map {
index in compactMap { $0.indices ~= index ? $0[index] : nil }
}
}
}
let dict = ["a": [1,2,3],
"b": [4,5,6],
"c": [7,8,9]]
let sorted = dict.sorted(by: {$0.key < $1.key})
let result = sorted.map(\.key).joined(separator: ",") + "\n" +
sorted.map(\.value).transposed().map {
$0.map(String.init).joined(separator: ",")
}.joined(separator: "\n")
result // "a,b,c\n1,4,7\n2,5,8\n3,6,9"
A dictionary is an unordered collection so you need to sort it according to any specific key. Here I sort the dictionary according to the key if you don't care about an order you can just remove sort.
let dict: [String: Any] = ["a": [1,2], "b": [3,4], "c": [5,6]]
let sortedKey = dict.keys.sorted(by: <)
let key = sortedKey.joined(separator: ",")
var firstValues: [String] = []
var secondValues: [String] = []
sortedKey.forEach { (key) in
if let dictValue = dict[key] as? [Int],
let firstValue = dictValue.first,
let secondValue = dictValue.last {
firstValues.append("\(firstValue)")
secondValues.append("\(secondValue)")
}
}
let finalString = key + "\n" + firstValues.joined(separator: ",") + "\n" + secondValues.joined(separator: ",")
print(finalString) // "a,b,c\n1,3,5\n2,4,6"

How to update nested dictionary in swift [duplicate]

This question already has answers here:
How to update a value in a nested dictionary given path fragment in Swift?
(2 answers)
Closed 3 years ago.
I have nested dictionary, so something like this:
var dict = ["a":["b":"c", "d":["e":"f"]], "f":["b":"g"]] // and more
Now if I want to update the value of key a.d.e, how should I do that?
It seems updateValue method only reads key as it is...It doesn't know anything about the nested key.
Edit:
While I really want to change the structure of this data to something easier to work with. I can't. This belongs to another class and I am not allow to change the structure, all I can do is to update it.
Second Edit:
After some thoughts and read the other question some one point out might be a duplicate, tried recursively updating. I feel this is seriously the worst way to do it because essentially it's creating new dictionaries with a copy of original value and assign it back. I do think it is a waste of space and tbh even recursively calling this I feel is unnecessary.
func updateKey(key:[AnyHashable],val:Bool,data:[AnyHashable:Any])->[AnyHashable:Any]{
var keyTemp = key
var tempData = data
if(keyTemp.count==1){
tempData.updateValue(val, forKey: key[0])
print(tempData)
return tempData
}else{
var firstLayerValue = data[keyTemp[0]] as? [AnyHashable:Any]
var firstKey = keyTemp.removeFirst()
var tempResult = updateKey(key: keyTemp, val: val, data: firstLayerValue!)
tempData.updateValue(tempResult, forKey: firstKey)
return tempData;
}
}
This returns a copy of what I intend to do, and I have to actually assign it back to the original copy. I really don't like this assigning back and forth thing, what if something went wrong in the middle then I might just end up losing the originally correct data.
Is there any better solution?
Another way of doing it
dict["a"]?["d"] = ["e": 123]
print(dict)
Outputs
["f": ["b": "g"], "a": ["b": "c", "d": ["e": 123]]]
Structs are the way to go. But if you really have to use dictionaries, here is a workaround:
var dict: [AnyHashable: Any] =
["a": ["b": "c", "d": ["e":"f"]],
"f": ["b": "g"]]
let newValue = true
if var firstLevel = dict["a"] as? [String : Any],
var secondLevel = firstLevel["d"] as? [String: Any] {
secondLevel["e"] = newValue
firstLevel["d"] = secondLevel
dict["a"] = firstLevel
}
print(dict) //[AnyHashable("a"): ["d": ["e": true], "b": "c"], AnyHashable("f"): ["b": "g"]]
To update a value in a dictionary with multiple levels, you can define a function like so:
func update(dictionary dict: inout [AnyHashable: Any], at keys: [AnyHashable], with value: Any) {
if keys.count < 2 {
for key in keys { dict[key] = value }
return
}
var levels: [[AnyHashable: Any]] = []
for key in keys.dropLast() {
if let lastLevel = levels.last {
if let currentLevel = lastLevel[key] as? [AnyHashable: Any] {
levels.append(currentLevel)
}
else if lastLevel[key] != nil, levels.count + 1 != keys.count {
break
} else { return }
} else {
if let firstLevel = dict[keys[0]] as? [AnyHashable : Any] {
levels.append(firstLevel )
}
else { return }
}
}
if levels[levels.indices.last!][keys.last!] != nil {
levels[levels.indices.last!][keys.last!] = value
} else { return }
for index in levels.indices.dropLast().reversed() {
levels[index][keys[index + 1]] = levels[index + 1]
}
dict[keys[0]] = levels[0]
}
And use it like so:
var dict: [AnyHashable: Any] = ["a": ["b": 1,
"c": ["d": ["e": "f"],
"g": ["h": 1.5]]],
"j": ["k": 2]]
update(dictionary: &dict,
at: ["a", "c", "d", "e"],
with: true)
dict.forEach { print($0) }
Here is the output in the console:
(key: AnyHashable("a"), value: [AnyHashable("b"): 1, AnyHashable("c"): [AnyHashable("d"): [AnyHashable("e"): true], AnyHashable("g"): ["h": 1.5]]])
(key: AnyHashable("j"), value: ["k": 2])

Get elements and count of Array of unknown type

Let's say we have an Array, assigned to a variable with the type Any
let something: Any = ["one", "two", "three"]
Let's also assume we don't know if it's an array or something entirely else. And we also don't know what kind of Array.Element we are dealing with exactly.
Now we want to find out if it's an array.
let isArray = something is Array // compiler error
let isArray = (something as? [Any?] != nil) // does not work (array is [String] and not [Any?])
Is there any elegant solution to tickle the following information out of the swift type system:
Is the given object an Array
What's the count of the array
Give me the elements of the array
(bridging to NSArray is not a solution for me, because my array could also be of type [Any?] and contain nil-values)
I love #stefreak's question and his solution. Bearing in mind #dfri's excellent answer about Swift's runtime introspection, however, we can simplify and generalise #stefreak's "type tagging" approach to some extent:
protocol AnySequenceType {
var anyElements: [Any?] { get }
}
extension AnySequenceType where Self : SequenceType {
var anyElements: [Any?] {
return map{
$0 is NilLiteralConvertible ? Mirror(reflecting: $0).children.first?.value : $0
}
}
}
extension Array : AnySequenceType {}
extension Set : AnySequenceType {}
// ... Dictionary, etc.
Use:
let things: Any = [1, 2]
let maybies: Any = [1, nil] as [Int?]
(things as? AnySequenceType)?.anyElements // [{Some 1}, {Some 2}]
(maybies as? AnySequenceType)?.anyElements // [{Some 1}, nil]
See Swift Evolution mailing list discussion on the possibility of allowing protocol extensions along the lines of:
extension<T> Sequence where Element == T?
In current practice, however, the more common and somewhat anticlimactic solution would be to:
things as? AnyObject as? [AnyObject] // [1, 2]
// ... which at present (Swift 2.2) passes through `NSArray`, i.e. as if we:
import Foundation
things as? NSArray // [1, 2]
// ... which is also why this fails for `mabyies`
maybies as? NSArray // nil
At any rate, what all this drives home for me is that once you loose type information there is no going back. Even if you reflect on the Mirror you still end up with a dynamicType which you must switch through to an expected type so you can cast the value and use it as such... all at runtime, all forever outside the compile time checks and sanity.
As an alternative to #milos and OP:s protocol conformance check, I'll add a method using runtime introspection of something (foo and bar in examples below).
/* returns an array if argument is an array, otherwise, nil */
func getAsCleanArray(something: Any) -> [Any]? {
let mirr = Mirror(reflecting: something)
var somethingAsArray : [Any] = []
guard let disp = mirr.displayStyle where disp == .Collection else {
return nil // not array
}
/* OK, is array: add element into a mutable that
the compiler actually treats as an array */
for (_, val) in Mirror(reflecting: something).children {
somethingAsArray.append(val)
}
return somethingAsArray
}
Example usage:
/* example usage */
let foo: Any = ["one", 2, "three"]
let bar: [Any?] = ["one", 2, "three", nil, "five"]
if let foobar = getAsCleanArray(foo) {
print("Count: \(foobar.count)\n--------")
foobar.forEach { print($0) }
} /* Count: 3
--------
one
2
three */
if let foobar = getAsCleanArray(bar) {
print("Count: \(foobar.count)\n-------------")
foobar.forEach { print($0) }
} /* Count: 5
-------------
Optional("one")
Optional(2)
Optional("three")
nil
Optional("five") */
The only solution I came up with is the following, but I don't know if it's the most elegant one :)
protocol AnyOptional {
var anyOptionalValue: Optional<Any> { get }
}
extension Optional: AnyOptional {
var anyOptionalValue: Optional<Any> {
return self
}
}
protocol AnyArray {
var count: Int { get }
var allElementsAsOptional: [Any?] { get }
}
extension Array: AnyArray {
var allElementsAsOptional: [Any?] {
return self.map {
if let optional = $0 as? AnyOptional {
return optional.anyOptionalValue
}
return $0 as Any?
}
}
}
Now you can just say
if let array = something as? AnyArray {
print(array.count)
print(array.allElementsAsOptional)
}
This works for me on a playground:
// Generate fake data of random stuff
let array: [Any?] = ["one", "two", "three", nil, 1]
// Cast to Any to simulate unknown object received
let something: Any = array as Any
// Use if let to see if we can cast that object into an array
if let newArray = something as? [Any?] {
// You now know that newArray is your received object cast as an
// array and can get the count or the elements
} else {
// Your object is not an array, handle however you need.
}
I found that casting to AnyObject works for an array of objects. Still working on a solution for value types.
let something: Any = ["one", "two", "three"]
if let aThing = something as? [Any] {
print(aThing.dynamicType) // doesn't enter
}
if let aThing = something as? AnyObject {
if let theThing = aThing as? [AnyObject] {
print(theThing.dynamicType) // Array<AnyObject>
}
}

How to use swift flatMap to filter out optionals from an array

I'm a little confused around flatMap (added to Swift 1.2)
Say I have an array of some optional type e.g.
let possibles:[Int?] = [nil, 1, 2, 3, nil, nil, 4, 5]
In Swift 1.1 I'd do a filter followed by a map like this:
let filtermap = possibles.filter({ return $0 != nil }).map({ return $0! })
// filtermap = [1, 2, 3, 4, 5]
I've been trying to do this using flatMap a couple ways:
var flatmap1 = possibles.flatMap({
return $0 == nil ? [] : [$0!]
})
and
var flatmap2:[Int] = possibles.flatMap({
if let exercise = $0 { return [exercise] }
return []
})
I prefer the last approach (because I don't have to do a forced unwrap $0!... I'm terrified for these and avoid them at all costs) except that I need to specify the Array type.
Is there an alternative away that figures out the type by context, but doesn't have the forced unwrap?
Since Swift 4.1 you can use compactMap:
let possibles:[Int?] = [nil, 1, 2, 3, nil, nil, 4, 5]
let actuals = possibles.compactMap { $0 }
(Swift 4.1 replaced some overloads of flatMap with compactmap.
If you are interested in more detail on this then see for example:
https://useyourloaf.com/blog/replacing-flatmap-with-compactmap/
)
With Swift 2 b1, you can simply do
let possibles:[Int?] = [nil, 1, 2, 3, nil, nil, 4, 5]
let actuals = possibles.flatMap { $0 }
For earlier versions, you can shim this with the following extension:
extension Array {
func flatMap<U>(transform: Element -> U?) -> [U] {
var result = [U]()
result.reserveCapacity(self.count)
for item in map(transform) {
if let item = item {
result.append(item)
}
}
return result
}
}
One caveat (which is also true for Swift 2) is that you might need to explicitly type the return value of the transform:
let actuals = ["a", "1"].flatMap { str -> Int? in
if let int = str.toInt() {
return int
} else {
return nil
}
}
assert(actuals == [1])
For more info, see http://airspeedvelocity.net/2015/07/23/changes-to-the-swift-standard-library-in-2-0-betas-2-5/
I still like the first solution, which creates only one intermediate
array. It can slightly more compact be written as
let filtermap = possibles.filter({ $0 != nil }).map({ $0! })
But flatMap() without type annotation and without forced
unwrapping is possible:
var flatmap3 = possibles.flatMap {
flatMap($0, { [$0] }) ?? []
}
The outer flatMap is the array method
func flatMap<U>(transform: #noescape (T) -> [U]) -> [U]
and the inner flatMap is the function
func flatMap<T, U>(x: T?, f: #noescape (T) -> U?) -> U?
Here is a simple performance comparison (compiled in Release mode).
It shows that the first method is faster, approximately by a factor
of 10:
let count = 1000000
let possibles : [Int?] = map(0 ..< count) { $0 % 2 == 0 ? $0 : nil }
let s1 = NSDate()
let result1 = possibles.filter({ $0 != nil }).map({ $0! })
let e1 = NSDate()
println(e1.timeIntervalSinceDate(s1))
// 0.0169369578361511
let s2 = NSDate()
var result2 = possibles.flatMap {
flatMap($0, { [$0] }) ?? []
}
let e2 = NSDate()
println(e2.timeIntervalSinceDate(s2))
// 0.117663979530334
Related to the question. If you are applying flatMap to an optional array, do not forget to optionally or force unwrap your array otherwise it will call flatMap on Optional and not objects conforming to Sequence protocol. I made that mistake once, E.g. when you want to remove empty strings:
var texts: [String]? = ["one", "two", "", "three"] // has unwanted empty string
let notFlatMapped = texts.flatMap({ $0.count > 0 ? $0 : nil })
// ["one", "two", "", "three"], not what we want - calls flatMap on Optional
let flatMapped = texts?.flatMap({ $0.count > 0 ? $0 : nil })
// ["one", "two", "three"], that's what we want, calls flatMap on Array
You could use reduce:
let flattened = possibles.reduce([Int]()) {
if let x = $1 { return $0 + [x] } else { return $0 }
}
You are still kind of declaring the type, but it's slightly less obtrusive.
Since this is something I seem to end up doing quite a lot I'm exploring a generic function to do this.
I tried to add an extension to Array so I could do something like possibles.unwraped but couldn't figure out how to make an extension on an Array. Instead used a custom operator -- hardest part here was trying to figure out which operator to choose. In the end I chose >! to show that the array is being filtered > and then unwrapped !.
let possibles:[Int?] = [nil, 1, 2, 3, nil, nil, 4, 5]
postfix operator >! {}
postfix func >! <T>(array: Array<T?>) -> Array<T> {
return array.filter({ $0 != nil }).map({ $0! })
}
possibles>!
// [1, 2, 3, 4, 5]