Dan Dan
Dan Dan

Reputation: 86

Swift array map without $0 (Higher-Order Functions )

I have a function that generates a number with some conditions

func randomWithCondition() -> Int {
  ...
  return n
}

And later I will use this function to build an array with N length in another function

func a() -> [Int] {
  var arr = [Int]()
  for _ in 0..<length {
    arr.append(randomWithCondition())
  }
  return arr
}

I want to write those in one line, the best thing I can think of is

return (0..<N).map { _ in randomWithCondition() }

I have to add _ in because I didn't use $0, otherwise it won't compile.

Question: Is there a walk round to not write _ in? any other format would be fine as long as it's one line in the return statement.

Upvotes: 1

Views: 731

Answers (2)

iUrii
iUrii

Reputation: 13863

map transforms each element from its type to other so that the transformation requires the parameter in the closure. But for convenience you can omit this parameter by making extensions for Range and ClosedRange:

extension Range where Bound: Strideable, Bound.Stride: SignedInteger {
    public func map<T>(_ transform: () -> T)  -> [T] {
        map { _ in transform() }
    }
}

extension ClosedRange where Bound: Strideable, Bound.Stride: SignedInteger {
    public func map<T>(_ transform: () -> T)  -> [T] {
        map { _ in transform() }
    }
}

let range = (0..<10).map { arc4random() }
print(range)
// Outputs: [676946806, 482060909, 1553829324, 1660236508, 606395000, 268649066, 1438948568, 1995527535, 918698113, 505678702]

let closedRange = (0...9).map { arc4random() }
print(closedRange)
// Outputs: [20467139, 198204705, 1585520963, 2022302907, 2518334206, 3304761403, 3782378335, 3830286797, 2200585433, 2387902936]

Upvotes: 1

Sweeper
Sweeper

Reputation: 275075

You need to define some extra functions yourself.

For example, a const function (name is inspired by Haskell, but you can call it withParameter instead):

func const<T, U>(_ f: @escaping () -> U) -> ((T) -> U) {
    { _ in f() }
}

Then you can do:

return (0..<N).map(const(randomWithCondition))

I think you should also wrap this in a generate function:

func generate<T>(_ count: Int, generator: @escaping () -> T) -> [T] {
    (0..<count).map(const(generator))
}

Do note that you can also create lazy infinite sequences with sequence, rather than mapping a range.

Upvotes: 1

Related Questions