Swift Type Constraints Common Base Class - swift

We have a helper function that is like this:
func + <KeyType, ValueType>(left: [KeyType: ValueType], right: [KeyType: ValueType])
-> [KeyType: ValueType]
{
var map: [KeyType: ValueType] = [:]
for (key, value) in left {
map[key] = value
}
for (key, value) in right {
map[key] = value
}
return map
}
and we use it to combine two dictionaries easily like this:
let foo = ["fooKey" : "fooValue"]
let bar = ["barKey" : "barValue"]
let combine = foo + bar // ["fooKey": "fooValue", "barKey": "barValue"]
It works great because both "fooValue" and "barValue" is of type String. However, the following doesn't work with error
"Binary operator + cannot be applied to [String: String] and [String: Int]".
let foo = ["fooKey" : "fooValue"]
let bar = ["barKey" : 1]
let combine = foo + bar // Error!!!
Is there a way write the dictionary helper function so that when the type of the values doesn't match, find their parent/base class and use that as the return type?
Conceptually, something like this:
func + <KeyType, ValueType1:BaseValueType, ValueType2:BaseValueType>(left: [KeyType: ValueType1], right: [KeyType: ValueType2])
-> [KeyType: BaseValueType]
{
var map: [KeyType: BaseValueType] = [:]
for (key, value) in left {
map[key] = value
}
for (key, value) in right {
map[key] = value
}
return map
}

You can use protocols, which all Swift dictionary keys/values have to conform to, to be used in the structure:
func combine(lhs: [AnyHashable: Any], rhs: [AnyHashable: Any]) -> [AnyHashable: Any] {
var dictionary = Dictionary<AnyHashable,Any>()
lhs.forEach {
dictionary[$0.key] = $0.value
}
rhs.forEach {
dictionary[$0.key] = $0.value
}
return dictionary
}

Related

How to write generic function which the implementation access the property of type

I am trying to write a generic function in the the body of the function, it reads one of the property of the Type.
My function:
func doSomething<Key>(
_ key: Key
) -> Int {
let a = key.aProperty
return doSomethingElse(a)
}
and I have put different struct to doSomething as long as they have the 'aProperty' as one of its properties
struct A {
let a : String
let aProperty: String
}
struct B {
let b : String
let aProperty: String
}
let a = A()
let b = B()
doSomething<A>(a)
doSomething<B>(b)
But I get compiler error in my doSomething function saying 'Value of type 'Key' has no member 'aProperty' .
So can you please tell me what am I missing in defining my doSomething function?
You can use protocol.
func doSomethingElse(_ a: String) -> Int { 0 }
protocol HasAProperty {
var aProperty: String { get }
}
func doSomething<Key: HasAProperty>(
_ key: Key
) -> Int {
let a = key.aProperty
return doSomethingElse(a)
}
struct A: HasAProperty {
let a : String
let aProperty: String
}
struct B: HasAProperty {
let b : String
let aProperty: String
}
let a = A(a: "a", aProperty: "aProperty")
let b = B(b: "b", aProperty: "aProperty")
doSomething(a)
doSomething(b)

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"]

How to check if two [String: Any] are identical?

Is there any way to check if two [String: Any] are identical ?
let actual: [[String: Any]] = [
["id": 12345, "name": "Rahul Katariya"],
["id": 12346, "name": "Aar Kay"]
]
var expected: [[String: Any]]!
if actual == expected {
print("Equal")
}
Basically i want Dictionary to conform to Equatable protocol in Swift 3.
For Xcode 7.3, swift 2.2
A dictionary is of type : [String:AnyObject] or simply put NSDictionary
let actual: [String: AnyObject] = ["id": 12345, "name": "Rahul Katariya"]
var expected: [String: AnyObject] = ["id": 12346, "name": "Aar Kay"]
print(NSDictionary(dictionary: actual).isEqualToDictionary(expected))//False
For Xcode 8.beta 6, Swift 3
Dictionary is defined as:
struct Dictionary<Key : Hashable, Value> : Collection, ExpressibleByDictionaryLiteral
NSDictionary has the following convenience initializer:
convenience init(dictionary otherDictionary: [AnyHashable : Any])
So you can use AnyHashable type for Key and Any type for Value
let actual: [String: Any] = ["id": 12345, "name": "Rahul Katariya"]
var expected: [String: Any] = ["id": 12346, "name": "Aar Kay"]
print(NSDictionary(dictionary: actual).isEqual(to: expected))//False
Conformance to Equatable aside; for the exercise you could write your own isEqual function to compare two [T: Any] dictionaries for a subset of (Equatable) types that you know the value wrapped by Any is limited to. By attempted conversion to these types (e.g. in a switch statement, as below), you could compare the dictionary's values (for each given key) one by one after their conversion to these given types. E.g.
// Usable if the 'Any' values in your dict only wraps
// a few different types _that are known to you_.
// Return false also in case value cannot be successfully
// converted to some known type. This might yield a false negative.
extension Dictionary where Value: Any {
func isEqual(to otherDict: [Key: Any],
allPossibleValueTypesAreKnown: Bool = false) -> Bool {
guard allPossibleValueTypesAreKnown &&
self.count == otherDict.count else { return false }
for (k1,v1) in self {
guard let v2 = otherDict[k1] else { return false }
switch (v1, v2) {
case (let v1 as Double, let v2 as Double) : if !(v1.isEqual(to: v2)) { return false }
case (let v1 as Int, let v2 as Int) : if !(v1==v2) { return false }
case (let v1 as String, let v2 as String): if !(v1==v2) { return false }
// ... fill in with types that are known to you to be
// wrapped by the 'Any' in the dictionaries
default: return false
}
}
return true
}
}
Usage:
/* example setup */
var dict1: [String: Any] = ["id": 12345, "name": "Rahul Katariya", "weight": 70.7]
var dict2: [String: Any] = ["id": 12346, "name": "Aar Kay", "weight": 83.1]
/* example usage */
print(dict1.isEqual(to: dict2, allPossibleValueTypesAreKnown: true))
// false
dict2["name"] = "Rahul Katariya"
dict2["weight"] = 70.7
print(dict1.isEqual(to: dict2, allPossibleValueTypesAreKnown: true))
// false
dict2["id"] = 12345
print(dict1.isEqual(to: dict2, allPossibleValueTypesAreKnown: true))
// true
class Foo {}
dict1["id"] = Foo()
dict2["id"] = Foo()
print(dict1.isEqual(to: dict2, allPossibleValueTypesAreKnown: true))
// false! (we haven't implemented this attempted conversion!)
// incompatable keys cause error as expected an intended
let dict3: [Int: Any] = [1:2]
dict1.isEqual(to: dict3)
/* error: cannot convert value of type '[Int : Any]'
to expected argument type '[String : Any]' */
Just note the danger that the as conversion may yield a false positive (true) as it can allow mapping from two different types to a common other type, e.g. slicing away derived class differences when casting two derived class instances to their common parent type:
class Base: Equatable {}
func ==(lhs: Base, rhs: Base) -> Bool { return true }
class DerivedA : Base {
let foo = "foo"
}
class DerivedB : Base {
let bar = 4.2
}
let a = DerivedA()
let b = DerivedB()
switch (a, b) {
case (let a as Base, let b as Base): print(a == b)
default: ()
} // sliced by conversion! prints "true"
If you'd rather like a failed "known types conversion" to return nil (whereas successful conversions will always yield true/false, based on subsequent equality testing), you could extend the above to (the even messier)
// a 'nil' return here would correspond to an invalid call
extension Dictionary where Value: Any {
func isEqual(to otherDict: [Key: Any],
allPossibleValueTypesAreKnown: Bool = false) -> Bool? {
guard allPossibleValueTypesAreKnown else { return nil }
guard self.count == otherDict.count else { return false }
for (k1,v1) in self {
guard let v2 = otherDict[k1] else { return false }
switch (v1, v2) {
case (let v1 as Double, let v2 as Double) : if !(v1.isEqual(to: v2)) { return false }
case (let v1 as Int, let v2 as Int) : if !(v1==v2) { return false }
case (let v1 as String, let v2 as String): if !(v1==v2) { return false }
// ...
case (_ as Double, let v2): if !(v2 is Double) { return false }
case (_, _ as Double): return false
case (_ as Int, let v2): if !(v2 is Int) { return false }
case (_, _ as Int): return false
case (_ as String, let v2): if !(v2 is String) { return false }
case (_, _ as String): return false
default: return nil
}
}
return true
}
}
/* Example as per above will yield (printout):
Optional(false)
Optional(false)
Optional(true)
nil */
Note however that the value by value equality testing above is short-circuited in case of a false hit, which mean that depending on the random order of the non-ordered dictionaries (non-ordered collection), a special case may return nil as well as false, given two non-equal dictionaries. This special case occurs for two dictionary of non-equal values (non-equality for a known type value-value pair) which also hold an value type not included in the attempted casting: if the non-equality of known types is hit first, false will be returned, whereas if a failed conversion is hit first, nil will be returned. Either way, a nil return means the call should be considered invalid, as caller stated that allPossibleValueTypesAreKnown was true (which a failed conversion implies is false).
The type Any is not Equatable in Swift, so any collection types including Any cannot be Equatable.
You can write something like this in Swift 3/Xcode 8 beta 6:
if actual as NSArray == expected as NSArray {
print("Equal")
}
But, as importing id as Any is just introduced in beta 6, so this behaviour may change in the near future.
With Swift 5.5 you can easily cast it to NSDictionary, as it always succeeds:
XCTAssertEqual(actual as NSDictionary, expected as NSDictionary)

Tuple-type in Swift generic constraint

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