How to extension HalfOpenInterval with reduce method - swift

I hope to extension HalfOpenInterval with reduce method
so can easy use some quick code snippet
for example:
var a = [3,4,9,7]
var mini = (0..<a.count).reduce(0, combine: { a[$0] > a[$1] ? $0 : $1 })
I notice that HalfOpenInterval fit IntervalType protocol, but not sure how to iterative each element in reduce function
extension HalfOpenInterval {
func reduce<T>(initialize: T, combine: (u: U, t:T) -> U) -> U {
...
}
}
tks

Maybe, what you should extend is Range:
extension Range {
func reduce<U>(initial:U, combine:(U, T) -> U) -> U {
return Swift.reduce(self, initial, combine)
}
}
let sum = (0 ..< 12).reduce(0, combine: { $0 + $1}) // -> 66
HalfOpenInterval or ClosedInterval is not for that, because it has only "start" and "end" values, but does not have "stride" of each values. Something like this:
Range also has "start" and "end", and these values itself know the next value of them:
Another similar structure, StrideTo and StrideThrough which constructed with stride(from:to:by:) or stride(from:through:by). It also has "start" and "end", and in this case, structure itself knows the "stride" between values.

You can extend the Range class in the following way.
extension Range {
func reduce<U>(initialize: U, combine: (u: U, t:T) -> U) -> U {
var result = initialize
for value in self {
result = combine(u: result,t: value)
}
return result
}
}

Related

Defining a generic unfoldr function

func unfoldr<A, B>(_ f: #escaping (B) -> (A, B)?) -> (B) -> UnfoldFirstSequence<A> {
return { b in sequence(
first: b, next: { x in
switch f(x) {
case .some(let(a, b)):
return Optional(a)
default:
return Optional.none
}
}
)
}
}
With this definition, I am getting the following error:
Cannot convert value of type 'B' to expected argument type 'A'.
Is there some way of solving this issue and definining this function ?
Your sequence doesn't seem to be a UnfoldFirstSequence. Your sequence seems to have a state B, and f is responsible for producing a new state and an element for the sequence. An UnfoldFirstSequence has no state that you can control. You can only produce the next element from the previous element.
Your sequence can be modelled by the more general UnfoldSequence, which has a State generic parameter. In fact, an UnfoldFirstSequence<T> is just an UnfoldSequence<T, (T?, Bool)>! See why the former is a special case of the latter by reading the source code :)
You can create such a sequence using sequence(state:next:).
func unfoldr<A, B>(_ f: #escaping (B) -> (A, B)?) -> (B) -> UnfoldSequence<A, B> {
return {
sequence(state: $0) { x in
guard let (a, b) = f(x) else {
return nil
}
x = b
return a
}
}
}
Example:
let seq = unfoldr { x -> (String, Int)? in
if x == 10 {
return nil
} else {
return ("\(x)", x + 1)
}
}
seq(0).forEach { print($0) }

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 do I write map that works for all types in Swift?

As an exercise, I'm implementing a map function that takes an array and a function and applies the function to all elements of the array, but I don't know how to declare it such that it works for any type of array.
I can do something like
func intMap(var arr: [Int], fun: (Int) -> Int) -> [Int] {
for i in 0 ..< arr.count {
arr[i] = fun(arr[i])
}
return arr
}
intMap([1,2,3], {x in return x * x})
But this only works for int.
What is the type signature for Swift's built-in map?
Edit:
So I was missing the fact that I can declare param type signatures without declaring their types explicitly.
func myMap<T>(var arr: [T], fun: (T) -> T) -> [T] {
for i in 0 ..< arr.count {
arr[i] = fun(arr[i])
}
return arr
}
myMap([1,2,3], fun: {
x in return x * x
})
Create a new Playground
Just under where it has import UIKit type import Swift
Command click on the word Swift
This will open the Swift library and you can see all the type definitions there.
And you can see:
extension CollectionType {
/// Return an `Array` containing the results of mapping `transform`
/// over `self`.
///
/// - Complexity: O(N).
#warn_unused_result
#rethrows public func map<T>(#noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
Edited to add
Alternatively, you can write a more generalised map
func myMap<T, U>(var arr: [T], fun: T -> U) -> [U] {
var a: [U] = []
for i in 0 ..< arr.count {
a.append(fun(arr[i]))
}
return a
}
Which returns a new array, of a possibly different type, which you can see for yourself by putting this in your playground.
let a = [1, 2, 3]
let b = myMap(a, fun: { x in Double(x) * 2.1 })
a
b

Swift writing map, length, filter as reduce

As an exercise, I'm trying to write map, length and filter as a reduce function.
func map<T>(array: [T], f: (T->T)) -> [T] {
return array.reduce([]) {
(var seed, value) in
seed.append(f(value))
return seed
}
}
func length<T>(array: [T]) -> Int {
return array.reduce(0){ (x,_) in x + 1 }
}
func filter<T>(array: [T], predicate: (T->Bool)) -> [T]{
return array.reduce([]){
(var seed, value) in
if predicate(value){
seed.append(value)
}
return seed
}
}
Is this the most elegant syntax I can use to rewrite those functions as reduce?
2nd question: map takes a function f:(T->T)
Basically the type says I can only return something of type T, but what if the function I write transforms type T to a Bool, or and Int...
How do I accomplish this?
Seems like map doesn't exist
For a mapping which transforms a type T into a (possibly different) type S
simply use two type placeholders:
func map<T, S>(array: [T], f: (T->S)) -> [S] {
return array.reduce([]) {
(var seed, value) in
seed.append(f(value))
return seed
}
}
Example:
let x = map([1, 2, 3], f: { String($0) })
print(x) // ["1", "2", "3"]
Whether this "is this the most elegant syntax" is also a
matter of personal opinion. If you replace the append() method
by array concatenation with + then the seed parameters needs
not be variable:
func map<T, S>(array: [T], f: (T->S)) -> [S] {
return array.reduce([]) {
(seed, value) in
seed + [f(value)]
}
}
Which can be written with shorthand parameter names as
func map<T, S>(array: [T], f: (T->S)) -> [S] {
return array.reduce([]) { $0 + [ f($1) ] }
}
Similarly:
func filter<T>(array: [T], predicate: (T->Bool)) -> [T]{
return array.reduce([]) { predicate($1) ? $0 + [ $1 ] : $0 }
}
Just note that an implementation of map() and filter() using
reduce() (instead of a loop) is quite ineffective because a new array is created in each reduction step. See for example
Arrays, Linked Lists and Performance
for an analysis. For an exercise (as you said) it is fine, just
don't use something like this in production).
extension CollectionType
extension CollectionType {
func MyMap<T>(transform: (Self.Generator.Element) -> T) -> [T] {
let list = self.reduce([T]()) { (var seed, value) in
seed.append(transform(value))
return seed
}
return list
}}
then use [1,2,3].MyMap({ $0 + 1})

Why is generic type information lost in generic functions with a Comparable constraint?

When creating a normal generic function without constraints it works as intended, i.e:
func select<T,U>(x:T, f:(T) -> U) -> U {
return f(x)
}
The type flows through into the closure argument where it lets me access it as the strong type, i.e:
var b1:Bool = select("ABC") { $0.hasPrefix("A") }
var b2:Bool = select(10) { $0 > 0 }
It continues to work when I add an Equatable constraint:
func selectEquatable<T : Equatable, U : Equatable>(x:T, f:(T) -> U) -> U {
return f(x)
}
var b3:Bool = selectEquatable("ABC") { $0.hasPrefix("A") }
But for some reason fails when using a Comparable constraint:
func selectComparable<T : Comparable, U : Comparable>(x:T, f:(T) -> U) -> U {
return f(x)
}
var b4:Bool = selectComparable("ABC") { $0.hasPrefix("A") }
Fails with the build error:
Could not find member 'hasPrefix'
But it does allow returning itself where the type flows through as a String
var b5:String = selectComparable("ABC") { $0 }
Looking at the API docs shows that String is Comparable:
extension String : Comparable {
}
and it even allows implicit casting from a String to a Comparable:
var str:Comparable = ""
So why can't I access it as a strong-typed String inside my Closure?
var b4:Bool = selectComparable("ABC") { $0.hasPrefix("A") } //build error
It's not the String. Your closure { $0.hasPrefix("A") } has the return type Bool, which is assigned to U. Bool is Equatable, but not Comparable.
You probably want the closure to return Bool, but selectComparable to return U.
Edit
Here's evidence that returning a String (which is Comparable) instead of a Bool (not Comparable) will compile:
func selectComparable<T: Comparable, U: Comparable>(x:T, f:(T) -> U) -> U {
return f(x)
}
var b4 = selectComparable("ABC") { (str: String) -> String in str }
Your selectComparable declaration is incorrect.
func selectComparable<T: Comparable, U: Comparable>(x:T, f:(T) -> U) -> U {
return f(x)
}
U: Comparable cannot hold for type Bool, it is not Comparable, only Equatable
This will work fine
func selectComparable<T: Comparable, U>(x:T, f:(T) -> U) -> U {
return f(x)
}
as will
func select<T:Comparable,U: Equatable>(x:T, f:(T) -> U) -> U {
return f(x)
}