Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift writing map, length, filter as reduce

Tags:

function

swift

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

like image 260
Seneca Avatar asked Sep 30 '15 18:09

Seneca


1 Answers

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).

like image 192
Martin R Avatar answered Oct 11 '22 13:10

Martin R