I am serialising some json into objects with a failable json initialiser like this:
sections = {
let sectionJsons = json["sections"] as! [[String:AnyObject]]
return sectionJsons.map {
DynamicSection($0)
}
}()
DynamicSection's init:
init?(_ json:[String:AnyObject]) {
super.init()
//Boring stuff that can fail
I want to only append the DynamicSections that passed the init to sections. How can I accomplish this?
I can use filter+map like
return sectionJsons.filter { DynamicSection($0) != nil }.map { DynamicSection($0)! }
But that leads to initing the DynamicSection twice, which i'd like to avoid. Is there any better way to do this?
You can use flatMap:
return sectionJsons.flatMap { DynamicSection($0) }
Example:
struct Foo {
let num: Int
init?(_ num: Int) {
guard num % 2 == 0 else { return nil }
self.num = num
}
}
let arr = Array(1...5) // odd numbers will fail 'Foo' initialization
print(arr.flatMap { Foo($0) }) // [Foo(num: 2), Foo(num: 4)]
// or, point to 'Foo.init' instead of using an anonymous closure
print(arr.flatMap(Foo.init)) // [Foo(num: 2), Foo(num: 4)]
Whenever you see a chained filter and map, flatMap can generally be used as a good alternative approach (not just when using the filter to check nil entries).
E.g.
// non-init-failable Foo
struct Foo {
let num: Int
init(_ num: Int) {
self.num = num
}
}
let arr = Array(1...5) // we only want to use the even numbers to initialize Foo's
// chained filter and map
print(arr.filter { $0 % 2 == 0}.map { Foo($0) }) // [Foo(num: 2), Foo(num: 4)]
// or, with flatMap
print(arr.flatMap { $0 % 2 == 0 ? Foo($0) : nil }) // [Foo(num: 2), Foo(num: 4)]
For Swift 3.0 and above:
return sectionJsons.compactMap { DynamicSection($0) }
Related
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)")
}
I can write Iterators as follows:
enum Stage { case a, ab, end }
struct SetMaker<Input: Hashable>: Sequence, IteratorProtocol {
var a,b: Input
var stage = Stage.a
init(a: Input, b: Input) {
self.a = a
self.b = b
}
mutating func next() -> Set<Input>? {
switch stage {
case .a: stage = .ab; return Set<Input>([a])
case .ab: stage = .end; return Set<Input>([a,b])
case .end: return nil
}
}
}
let setMaker = SetMaker(a: "A", b: "B")
for x in setMaker {
print(x)
}
struct ArrayMaker<Input: Hashable>: Sequence, IteratorProtocol {
var a: Input
var b: Input
var stage = Stage.a
init(a: Input, b: Input) {
self.a = a
self.b = b
}
mutating func next() -> Array<Input>? {
switch stage {
case .a: stage = .ab; return Array<Input>([a])
case .ab: stage = .end; return Array<Input>([a,b])
case .end: return nil
}
}
}
let arrayMaker = ArrayMaker(a: "A", b: "B")
for x in arrayMaker {
print(x)
}
The first returning a sequence of Sets and the second returning a sequence of Arrays.
These both work fine but I like to keep my code "DRY" (i.e. Don't Repeat Yourself).
So I'd like to do write something Generic that will allow construction of either.
My attempt is:
struct AnyMaker<Input: Hashable, CollectionType>: Sequence, IteratorProtocol {
var a,b: Input
var stage = Stage.a
init(a: Input, b: Input) {
self.a = a
self.b = b
}
mutating func next() -> CollectionType<Input>? {
switch stage {
case .a: stage = .ab; return CollectionType<Input>([a])
case .ab: stage = .end; return CollectionType<Input>([a,b])
case .end: return nil
}
}
}
But this doesn't compile.
Any help appreciated :-)
Edit...
#Rob made a good suggestion which gets me part way there - see his answer.
But if I want the Collection to be a Set sometimes then there's an issue because Set is not RangeReplaceable.
To put it another way I've created a slightly different bit of code:
struct Pairs<C>: Sequence, IteratorProtocol
where C: RangeReplaceableCollection {
var collection: C
var index: C.Index
init(_ collection: C) {
self.collection = collection
index = self.collection.startIndex
}
mutating func next() -> C? {
guard index < collection.endIndex else { return nil }
let element1 = collection[index]
index = collection.index(after: index)
guard index < collection.endIndex else { return nil }
let element2 = collection[index]
let pair = [element1,element2]
return C(pair)
}
}
do {
print("Pairs from array")
let array = ["A","B","C"]
let pairs = Pairs(array) //This line is fine
for pair in pairs {
print(pair)
}
}
do {
print("Pairs from set")
let set = Set(["A","B","C"])
let pairs = Pairs(set) // This line causes error
for pair in pairs {
print(pair)
}
}
The line "let pairs = Pairs(set)" generates an error:
"Argument type 'Set' does not conform to expected type 'RangeReplaceableCollection'"
So I need to work out how to instantiate a collection without using RangeReplaceableCollection?
You never restricted the type of CollectionType, so Swift doesn't know you can create one at all, let alone create one by passing an array. Collection itself doesn't promise any init methods, either. We need to go to RangeReplaceableCollection to get that:
struct AnyMaker<CollectionType>: Sequence, IteratorProtocol
where CollectionType: RangeReplaceableCollection {
typealias Input = CollectionType.Element
...
}
Once you've done that, next() looks like this:
mutating func next() -> CollectionType? {
switch stage {
case .a: stage = .ab; return CollectionType([a])
case .ab: stage = .end; return CollectionType([a,b])
case .end: return nil
}
}
Note that this returns CollectionType? not CollectionType<Input>?. Nothing about CollectionType requires that it take a type parameter, so we can't pass one. There's no way to express "takes a type parameter" even if we wanted it, but we don't want it. CollectionType just has to have some Element, and that's promised by RangeReplaceableCollection.
let anyMaker = AnyMaker<[String]>(a: "A", b: "B")
for x in arrayMaker {
print(x)
}
Full code:
struct AnyMaker<CollectionType>: Sequence, IteratorProtocol
where CollectionType: RangeReplaceableCollection {
typealias Input = CollectionType.Element
var a,b: Input
var stage = Stage.a
init(a: Input, b: Input) {
self.a = a
self.b = b
}
mutating func next() -> CollectionType? {
switch stage {
case .a: stage = .ab; return CollectionType([a])
case .ab: stage = .end; return CollectionType([a,b])
case .end: return nil
}
}
}
Even though Collection doesn't require an initialiser, Array and Set do have the initialiser we want:
init<S : Sequence>(_ elements: S) where S.Element == Element
so by creating a new procotol which requires this and then extending Array and Set with this protocol we can then assume that UsableCollections will have this initialiser and all works as required:
protocol UsableCollection: Collection {
init<S : Sequence>(_ elements: S) where S.Element == Element
}
extension Array: UsableCollection { }
extension Set: UsableCollection { }
struct Pairs<C: UsableCollection>: Sequence, IteratorProtocol {
var collection: C
var index: C.Index
init(_ collection: C) {
self.collection = collection
index = self.collection.startIndex
}
mutating func next() -> C? {
guard index < collection.endIndex else { return nil }
let element1 = collection[index]
index = collection.index(after: index)
guard index < collection.endIndex else { return nil }
let element2 = collection[index]
let pair = [element1,element2]
return C(pair)
}
}
do {
print("Pairs from array")
let array = ["A","B","C"]
let pairs = Pairs(array)
for pair in pairs {
print(pair)
}
}
do {
print("Pairs from set")
let set = Set(["A","B","C"])
let pairs = Pairs(set)
for pair in pairs {
print(pair)
}
}
Here's the code I try to make work
struct A {
var x:Int = 0
}
struct B {
var y:Int = 0
}
var c: [String:Any] = [
"a":[A()],
"b":[B()]
]
for (key, value) in c {
let arr = value as! [Any]
}
It just throws exception. The runtime exception is raised when trying to cast Any to [Any].
The main thing I want to achieve is iterate through the elements of Any, if Any is array. To me it was natural to cast Any to [Any], but for some reason it doesn't work. So how can I do this in obvious thing in swift?
I saw some workarounds to cast Any to [A] or [B], but that's not my case, because the array can contain just an arbitrary struct.
You can make use of runtime introspection to inspect whether values in your dictionary are of collection type, and if so, iterate over their children (= elements, for array case), and append these to an actual array of Any, in so letting Swift know some Any values in your dictionary are actually arrays.
/* Example setup */
struct A {
var x: Int
init(_ x: Int) { self.x = x }
}
struct B {
var y: Int
init(_ y: Int) { self.y = y }
}
var c: [String:Any] = [
"a": [A(1), A(2)],
"b": [B(3)],
"c": "JustAString",
"d": A(0)
]
E.g. as follows
/* runtime introspection to extract array values from dictionary */
var commonAnyArr: [[Any]] = []
for (_, value) in c {
if case let m = Mirror(reflecting: value)
where (m.displayStyle ?? .Struct) == .Collection {
let arr = m.children.map { $0.value }
commonAnyArr.append(arr)
}
}
/* resulting array of any arrs, that Swift now recognize as actual arrays */
commonAnyArr.forEach { print($0) }
/* [B(y: 3)]
[A(x: 1), A(x: 2)] */
commonAnyArr.flatten().forEach { print($0) }
/* B(y: 3)
A(x: 1)
A(x: 2) */
Alternatively, use the runtime introspection to construct a new dictionary, containing only the key-value pairs of c where the underlying value wrapped by the Any value is in fact an array (however in the new dictionary explicitly specifying for swift that the values are arrays of Any).
/* runtime introspection to extract array values from dictionary */
var dictOfAnyArrs: [String: [Any]] = [:]
for (key, value) in c {
if case let m = Mirror(reflecting: value)
where (m.displayStyle ?? .Struct) == .Collection {
let arr = m.children.map { $0.value }
dictOfAnyArrs[key] = arr
}
}
/* "remaining" dictionary keys now only with [Arr] values */
for (key, arr) in dictOfAnyArrs {
for element in arr {
print("Do something with element \(element)")
}
print("---")
}
/* Do something with element B(y: 3)
---
Do something with element A(x: 1)
Do something with element A(x: 2)
--- */
Just note that the above could be considered somewhat "hacky" (in the eyes of Swift and its pride in static typing and runtime safety), and possibly mostly interesting more out of a technical aspect rather than to be used in actual production code (I would personally never allow anything like the above in production of my own). Perhaps if you take a step back and look at how you've reached this issue, you could re-work your code and design to not reach a point where you need to resort to runtime hacks.
Is there a nicer way to do the assignment to DEF in the following example? I want to convert type A to Type B, but still preserve the nil possibility whenever I can.
Can't seem to stumble into a better way of doing this, however. Suggestions?
class ABC {
var DEF: Int?
func X (someValue: Int8?) {
DEF = someValue != nil ? Int(someValue) : nil
}
}
Swift 1:
class ABC {
var DEF: Int?
func X (someValue: Int8?) {
DEF = someValue.map{Int($0)}
}
}
Swift 2:
class ABC {
var DEF: Int?
func X (someValue: Int8?) {
DEF = someValue.map(Int.init)
}
}
map() takes an optional, unwraps it, and applies a function to it. If the optional resolves to nil, map() returns nil.
You are describing optional map:
var i: Int? = 2
let j = i.map { $0 * 2 } // j = .Some(4)
i = nil
let k = i.map { $0 * 2 } // k = nil
Think of this map like array or other collection map, where optionals are collections that have either zero (nil) or one (non-nil) element.
Note, if the operation you want to perform itself returns an optional, you need flatMap to avoid getting a double-optional:
let s: String? = "2"
let i = s.map { Int($0) } // i will be an Int??
let j = s.flatMap { Int($0) } // flattens to Int?
I'm trying to write a generic function in Swift with the constraint that the parameter must be a sequence of pairs (which I'm going to turn into a dictionary). Is this possible? I've tried a number of variations on the following, but the compiler doesn't like any of them.
func foo<K, V, S: SequenceType where S.Generator.Element == (K,V)>(xs: S) { //...}
Not a direct answer to your question, but if you want to create
a dictionary then you could define your function as an extension
method to Dictionary and use the fact that Dictionary defines
typealias Element = (Key, Value)
Then your method declaration could be
extension Dictionary {
func foo<S : SequenceType where S.Generator.Element == Element>(xs : S) {
//...
}
}
To create a dictionary from the tuples, an init method might be more appropriate, for example
extension Dictionary {
init<S : SequenceType where S.Generator.Element == Element>(xs : S) {
self.init()
var gen = xs.generate()
while let (key, value) : Element = gen.next() {
self[key] = value
}
}
}
Usage:
let d = Dictionary(xs: [("a", 1), ("b", 2)])
println(d) // [b: 2, a: 1]
Note: The enumation via generate() and next() in above code
is a workaround for the problem that, for some reason
for (key, value) in xs { }
does not compile. Compare Implementing Set.addSequence in Swift.
Update: As of Swift 2/Xcode 7, the above method can be simplified
to
extension Dictionary {
init<S : SequenceType where S.Generator.Element == Element>(xs : S) {
self.init()
xs.forEach { (key, value) in
self[key] = value
}
}
}
It looks like a compiler bug to me.
Problem here is that: you cannot use tuple type directly in generic parameters.
As #MartinR said in his answer, it works if we use typealiased tuple type. But of course, we cannot declare generic typealias in global context.
For example, this compiles and works:
struct Foo<K,V> {
typealias Element = (K,V)
static func foo<S:SequenceType where S.Generator.Element == Element>(xs:S) {
var gen = xs.generate()
while let (k,v): Element = gen.next() {
println((k,v))
}
}
}
Foo.foo(["test":"foo", "bar": "baz"])
One more idea is something like this:
struct SequenceOfTuple<K,V>: SequenceType {
typealias Element = (K,V)
let _generate:() -> GeneratorOf<Element>
init<S:SequenceType where S.Generator.Element == Element>(_ seq:S) {
_generate = { GeneratorOf(seq.generate()) }
}
func generate() -> GeneratorOf<Element> {
return _generate()
}
}
func foo<K,V>(xs:SequenceOfTuple<K,V>) {
for (k, v) in xs {
println((k,v))
}
}
foo(SequenceOfTuple(["test":"foo", "bar": "baz"]))
In this case, you must wrap the sequence of tuple with SequenceOfTuple type, then pass it to foo().
Hmm...
You can use a struct with a subscript and store the results in a Dictionary:
struct Matrix<K:Hashable, V> {
var container:[K:[K:V]] = [:]
subscript(x:K, y:K) -> V? {
get {
return container[x]?[y]
}
set (value) {
if container[x] == nil {
container[x] = [:]
}
container[x]![y] = value
}
}
}
var matrix = Matrix<Int, String>()
matrix[11,42] = "Hello World"
println("(11,42): \(matrix[11,42])") // Optional("Hello World")
println("(1,3): \(matrix[1,3])") // nil