Get first mapped result from array - swift

I have an array of functions like
let array = [(Int) -> T?, (Int) -> T?, (Int) -> T?,...]
I need to get first non nil T value from array and I want 1 iteration for this task (O(n) will be the worst complexity). Anybody has neat ideas without for loops?

As I mentioned in my comment, there's no ready-made way to do this in Swift, so you have to at least implement something that uses a for loop.
If you want appearances at the call-site to look functional and not use a for loop, you can make the function extend Array like so:
extension Array {
func firstNonNilResult<V, T>(value: V) -> T? where Element == (V) -> T? {
for element in self {
if let t = element(value) {
return t
}
}
return nil
}
}
var array = [(Int) -> String?]()
func f(_ i: Int) -> String? {
print("called f() with \(i)")
return nil
}
func g(_ i: Int) -> String? {
print("called g() with \(i)")
return i == 5 ? "found it" : nil
}
array.append(f)
array.append(g)
if let t = array.firstNonNilResult(value: 5) {
print(t)
}
which prints:
called f() with 5
called g() with 5
found it
Whether or not this has any real-world utility I can't say. I think it's specialized enough that an Array extension seems like overkill, but your question is interesting so this is at least a potential solution.

Related

problems with set on swift language

I have created a class that adopt Hashable protocol.
So I created some instances of this class with different properties and added them to the Set.
Then I change a property of an object.
After this change the Set sometimes fail .contains (and also .remove).
In the debugger inspector I see that the object has the same memory address of the element inside the Set. So why fail at random?
Note that I can always found the index of the element inside the set.
I tested with playground (on xcode10) several times and on every execution the results change.
class Test: Hashable {
// MARK: Equatable protocol
static func == (lhs: Test, rhs: Test) -> Bool {
return lhs === rhs || lhs.hashValue == rhs.hashValue
}
var s: String
func hash(into hasher: inout Hasher) {
hasher.combine(s.hashValue)
}
init(s: String) {
self.s = s
}
}
func test(s: Set<Test>, u: Test) -> Bool {
if s.contains(u) {
print("OK")
return true
} else {
print("FAIL") // SOMETIMES FAIL
if !s.contains(u) {
if let _ = s.firstIndex(where: { $0 == u }) {
print("- OK index") // ALWAYS OK
return true
} else {
print("- FAIL index") // NEVER FAIL
return false
}
} else {
return true
}
}
}
var s: Set<Test> = []
let u1 = Test(s: "a")
s.insert(u1)
let u2 = Test(s: "b")
s.insert(u2)
test(s: s, u: u2)
u2.s = "c"
test(s: s, u: u2)
u2.s = "d"
test(s: s, u: u2)
u2.s = "b"
test(s: s, u: u2)
From the docs on NSSet:
If mutable objects are stored in a set, either the hash method of the objects shouldn’t depend on the internal state of the mutable objects or the mutable objects shouldn’t be modified while they’re in the set.
I think that exactly covers this case. True, it's about Cocoa NSSet, but I would expect Swift Set to correspond to NSSet in this regard.
Just for the record, I was able to reproduce the behavior you describe, eliminating some of the skankier or more questionable code - not in a playground, with a legal implementation of == and using hashValue, and without the unnecessary call to a test function:
class Test: Equatable, Hashable, CustomStringConvertible {
var s: String
static func == (lhs: Test, rhs: Test) -> Bool {
return lhs.s == rhs.s
}
var hashValue: Int {
return s.hashValue
}
init(s: String) {
self.s = s
}
var description: String {
return "Test(\(s))"
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var s: Set<Test> = []
let u1 = Test(s: "a")
s.insert(u1)
let u2 = Test(s: "b")
s.insert(u2)
print(s.contains(u2))
u2.s = "c"
print(s.contains(u2))
}
}
To test it, run the project over and over. Sometimes you'll get true true and sometimes you'll get true false. The inconsistency is the indication that you shouldn't be mutating an object in a set.
Things in a set should be immutable.
You should never have put Test objects into a set because Test is completely mutable. This is exactly why you get these "strange and random" behaviour.
When you call contains, the set (or rather, the underlying hash table) evaluates the hash code of the parameter and see if the hash code matches any of the hash codes in the set. (Note that this is an oversimplification and it makes it sounds like this is a O(n) operation. It's not.)
Before you change u2, it has a hash code of x. The set remembers that u2 has a hash code of x. Now you change u2. It now has a different hash code y. The set thus can't find an element in it that has a hash code of y.
So basically, you should make sure that everything you put into a set has a constant hash code.
You can make Test immutable by doing:
let s: String
If you want to learn more you can look up how the set data structure is implemented in Swift. I found this post which might help as well.
Since you are using the s property of Test class to create the hash values, try comparing s values instead of comparing the objects, i.e.
static func == (lhs: Test, rhs: Test) -> Bool
{
return lhs.s == rhs.s
}
This will resolve your issue. Also, as I mentioned in the comment, there is no need to use an extra if-else in the failure case. You can simply use the below code:
func test(s: Set<Test>, u: Test) -> Bool
{
if s.contains(u)
{
print("OK")
return true
}
else
{
print("FAIL: \(u.s)") // SOMETIMES FAIL
return false
}
}

is there a more elegant syntax for Swift Filter with 2 parameters

Is there a more elegant way to filter with an additional parameter (or map, reduce).
When I filter with a single parameter, we get a beautiful easy to ready syntax
let numbers = Array(1...10)
func isGreaterThan5(number:Int) -> Bool {
return number > 5
}
numbers.filter(isGreaterThan5)
However, if I need to pass an additional parameter to my function it turns out ugly
func isGreaterThanX(number:Int,x:Int) -> Bool {
return number > x
}
numbers.filter { (number) -> Bool in
isGreaterThanX(number: number, x: 8)
}
I would like to use something like
numbers.filter(isGreaterThanX(number: $0, x: 3))
but this gives a compile error annonymous closure argument not contained in a closure
You could change your function to return a closure which serves
as predicate for the filter method:
func isGreaterThan(_ lowerBound: Int) -> (Int) -> Bool {
return { $0 > lowerBound }
}
let filtered = numbers.filter(isGreaterThan(5))
isGreaterThan is a function taking an Int argument and returning
a closure of type (Int) -> Bool. The returned closure "captures"
the value of the given lower bound.
If you make the function generic then it can be used with
other comparable types as well:
func isGreaterThan<T: Comparable>(_ lowerBound: T) -> (T) -> Bool {
return { $0 > lowerBound }
}
print(["D", "C", "B", "A"].filter(isGreaterThan("B")))
In this particular case however, a literal closure is also easy to read:
let filtered = numbers.filter( { $0 > 5 })
And just for the sake of completeness: Using the fact that
Instance Methods are Curried Functions in Swift, this would work as well:
extension Comparable {
func greaterThanFilter(value: Self) -> Bool {
return value > self
}
}
let filtered = numbers.filter(5.greaterThanFilter)
but the "reversed logic" might be confusing.
Remark: In earlier Swift versions you could use a curried function
syntax:
func isGreaterThan(lowerBound: Int)(value: Int) -> Bool {
return value > lowerBound
}
but this feature has been removed in Swift 3.

How to use first/head and rest/tail with Swift?

In order to use Swift in a functional style, how should we be dealing with head and tails of lists? Are Arrays and ArraySlices appropriate (seems like it since an ArraySlice is an efficient mechanism to get sublists)? Is the right mechanism to convert an Array to an ArraySlice and use .first! and .dropFirst() as equivalents for head and tail?
As an example of adding a list of numbers:
func add(_ nums: ArraySlice<Int>) -> Int {
if nums.count == 0 {
return 0
} else {
return nums.first! + add(nums.dropFirst())
}
}
Array has an initializer (init(_:)) that can produce an Array from any Sequence, such as an ArraySlice. However, using it forces a copy of the array data, which makes a simple sum algorithm like this to actually have O(nums.count^2) performance, even though it looks like it's only scanning through the array once.
func sum(_ nums: [Int]) -> Int {
guard let head = nums.first else { return 0 } //base case, empty list.
return head + sum(Array(nums.dropFirst()))
}
let input = Array(1...10)
let output = sum(input)
print(output)
To get around this, a better implementation would instead just operate on ArraySlices, allowing copy-less slicing, but that requires the input Array first be converted into an ArraySlice. Luckily, an inner function can help make this transparent to the public API, but it does make the code longer.
func sum(_ nums: [Int]) -> Int {
func sum(_ nums: ArraySlice<Int>) -> Int {
guard let head = nums.first else { return 0 } //base case, empty list.
return head + sum(nums.dropFirst())
}
return sum(ArraySlice(nums))
}
But really, as matt said, don't do this. The head/tail approach to programming makes sense in a language that facilitates it well with pattern matching, good compiler optimizations, tail call optimization, etc. Swift's design encourages using reduce. Not only is it shorter and much more readable, but it's also more performant.
For comparison, here's what a typical Swift approach would be to this:
extension Sequence where Iterator.Element: Integer {
func sum() -> Iterator.Element {
return self.reduce(0, +)
}
}
It's simpler and shorter.
It's polymorphic, so it'll work with any Sequence, rather than just being limited to Array
It's generic over any Integer type, not just Int. So these all work:
print(Array<UInt >(1...10).sum())
print(Array<UInt8 >(1...10).sum())
print(Array<UInt16>(1...10).sum())
print(Array<UInt32>(1...10).sum())
print(Array<UInt64>(1...10).sum())
print(Array< Int >(1...10).sum())
print(Array< Int8 >(1...10).sum())
print(Array< Int16>(1...10).sum())
print(Array< Int32>(1...10).sum())
print(Array< Int64>(1...10).sum())
However, if you insist on taking this head/tail approach, you can try one of these two techniques:
extension Collection {
func headTail1<Head, Tail, ReturnType>(_ closure: (Head?, Tail) -> ReturnType) -> ReturnType
where Head == Self.Element, Tail == Self.SubSequence {
return closure(self.first, self.dropFirst())
}
func headTail2<Head, Tail>() ->(Head?, Tail)
where Head == Self.Element, Tail == Self.SubSequence {
return (self.first, self.dropFirst())
}
}
func sum1<C: Collection, I: Numeric>(_ nums: C) -> I
where C.Element == I {
return nums.headTail1 { head, tail in
guard let head = head else { return 0 } //base case, empty list
return head + sum(tail)
}
}
func sum2<C: Collection, I: Numeric>(_ nums: C) -> I
where C.Element == I {
let (_head, tail) = nums.headTail2()
guard let head = _head else { return 0 } //base case, empty list
return head + sum(tail)
}
print(sum(Array(1...10)))
This code abstracts away the details of how the list is split into its head and tail, letting you write sum by only worrying about the head and tail that are provided for you.
The problem with your example is that you wouldn't use head and tail to add a list of numbers. You'd call reduce:
let nums = [1,2,3,4,5]
let sum = nums.reduce(0,+)
So, while I'm as fond of LISP / Scheme as the next man, you'll need a more compelling case of when we need head and tail, given that we have map, filter, and reduce (and so on).

Can I extend Tuples in Swift?

I'd like to write an extension for tuples of (e.g.) two value in Swift. For instance, I'd like to write this swap method:
let t = (1, "one")
let s = t.swap
such that s would be of type (String, Int) with value ("one", 1). (I know I can very easily implement a swap(t) function instead, but that's not what I'm interested in.)
Can I do this? I cannot seem to write the proper type name in the extension declaration.
Additionally, and I suppose the answer is the same, can I make a 2-tuple adopt a given protocol?
You cannot extend tuple types in Swift.
According to
Types, there are named types (which
can be extended) and compound types. Tuples and functions are compound
types.
See also (emphasis added):
Extensions
Extensions add new functionality to an existing
class, structure, or enumeration type.
As the answer above states, you cannot extend tuples in Swift. However, rather than just give you a no, what you can do is box the tuple inside a class, struct or enum and extend that.
struct TupleStruct {
var value: (Int, Int)
}
extension TupleStruct : Hashable {
var hashValue: Int {
return hash()
}
func hash() -> Int {
var hash = 23
hash = hash &* 31 &+ value.0
return hash &* 31 &+ value.1
}
}
func ==(lhs: TupleStruct, rhs: TupleStruct) -> Bool {
return lhs.value == rhs.value
}
As a side note, in Swift 2.2, tuples with up to 6 members are now Equatable.
Details
Xcode 11.2.1 (11B500), Swift 5.1
Solution
struct Tuple<T> {
let original: T
private let array: [Mirror.Child]
init(_ value: T) {
self.original = value
array = Array(Mirror(reflecting: original).children)
}
func getAllValues() -> [Any] { array.compactMap { $0.value } }
func swap() -> (Any?, Any?)? {
if array.count == 2 { return (array[1].value, array[0].value) }
return nil
}
}
Usage
let x = (1, "one")
let tuple = Tuple(x)
print(x) // (1, "one")
print(tuple.swap()) // Optional((Optional("one"), Optional(1)))
if let value = tuple.swap() as? (String, Int) {
print("\(value) | \(type(of: value))") // ("one", 1) | (String, Int)
}
If you wanted to be a Bad Person™ you can define custom operators on tuples, like this:
postfix operator <->
postfix func <-> <A, B>(lhs: (A, B)) -> (B, A) {
return (lhs.1, lhs.0)
}
let initial = (1, "one")
let reversed = initial<->
FWIW I can't think of a place where my 'clever' code trumps the readability of just writing your swap function.

Swift single argument with autoclosure without braces at all

I would like to achieve Haskell elem function with Apple Swift language.
This looks like not very hard to implement:
func elem<T: Equatable>(item: T) -> [T] -> Bool {
return { arr in find(arr, item) != nil }
}
elem(2)([1,2,3])
But I wanna to skip braces for arguments. It is possible for last(or single) argument of closure type:
func elem<T: Equatable>(item: ()->T) -> (()->[T]) -> Bool {
return { (arr: ()->[T]) in find(arr(), item()) != nil }
}
elem{2}{[1,2,3]}
But here we have an error:
Consecutive statements on a line must be separated by ':'
This error is a real problem, which looks like compiler imperfection. But we need to go deeper to avoid brackets {}, it can be achieved with #autoclosure:
func elem<T: Equatable>(item: #autoclosure ()->T) -> (#autoclosure ()->[T]) -> Bool {
return { (arr: #autoclosure ()->[T]) in find(arr(), item()) != nil }
}
elem 2 [1,2,3]
And we have the same error.
I think Swift compiler should not give me this errors. Are there any other ways to avoid braces and brackets?