Быстрое функциональное программирование - есть ли лучший способ перевести вложенный цикл for, чем два вызова карты

я преобразовал вложенный цикл for во вложенный вызов map. мне было интересно, есть ли более элегантный способ реализовать это.

вот функция, которая принимает Array из Items и Array функций (Item -> Item) и возвращает массив со всеми функциями, примененными к каждому элементу:

typealias Item = Dictionary<String, String>    

func updatedItems(items: Array<Item>, fns: Array<Item -> Item>) -> Array<Item> {
    return items.map {
        item in

        var itemCopy = item
        fns.map { fn in itemCopy = fn(itemCopy) }

        return itemCopy
    }
}

person H K    schedule 02.08.2015    source источник


Ответы (2)


Внутренний вызов map() не возвращает новый массив, это делается только для побочных эффектов. Это работает, но иногда «не одобряется» (см., например, Функция высшего порядка: невозможно вызвать 'map' со списком аргументов типа '((_) -> _)').

«Правильный» способ применить все функции по очереди к одному элементу — использовать reduce:

func updatedItems(items: Array<Item>, fns: Array<Item -> Item>) -> Array<Item> {
    return items.map {
        item in
        fns.reduce(item) {
            (curItem, fn) in
            fn(curItem)
        }
    }
}

или с сокращенными именами аргументов:

func updatedItems(items: Array<Item>, fns: Array<Item -> Item>) -> Array<Item> {
    return items.map {
        fns.reduce($0) { $1($0) }
    }
}

Обратите также внимание, что вы можете сократить запись массива до

func updatedItems(items: [Item], fns: [Item -> Item]) -> [Item] { ... }
person Martin R    schedule 02.08.2015

Другое решение — использовать enumerate, чтобы также иметь доступ к индексу.

return items.enumerate().map { (idx, item) in
   let fn = fns[idx] as <Item -> Item>
   return fn(item)
}
person Mundi    schedule 02.08.2015