Всем привет! На собеседованиях время от времени встречается вопрос как выравнить многоуровневый массив.

Если это простой двухуровневый массив вида [[1, 2], [3, 4]], то нам поможет стандартная функция высшего порядка flatMap().

Но что если нам нужно нужно выровнять более сложные массивы, например:

[1, [2]] -> [1, 2]

[1, [2, 3]] -> [1, 2, 3]

[1, [2, [3, [4]]]] -> [1, 2, 3, 4]

В этом случае мы можем написать свою рекурсивную функцию:

func flattFunction(array:[Any]) -> [Int] {
    var flattenArray = [Int]()
    
    for element in array {
        if let element = element as? Int {
            flattenArray.append(element)
        } else if let element = element as? [Any] {
            let result = flattFunction(array: element)
            flattenArray += result
        }
    }
    
    return flattenArray
}

Протестируем:

let arr1 = [1]
let arr2 = [1, 2, 3]
let arr3: [Any] = [1, [2]]
let arr4: [Any] = [1, [2, 3]]
let arr5: [Any] = [1, [2, [3, [4]]]]

func testFlattFunc() {
    print(flattFunction(array: arr1))
    print(flattFunction(array: arr2))
    print(flattFunction(array: arr3))
    print(flattFunction(array: arr4))
    print(flattFunction(array: arr5))
}

testFlattFunc()

// Вывод:
// [1]
// [1, 2, 3]
// [1, 2]
// [1, 2, 3]
// [1, 2, 3, 4]

Надеюсь это небольшая заметка окажется полезной.

Комментарии (2)


  1. Rorg
    12.04.2024 10:53
    +1

    В итоге никуда flatMap не делать. Старая версия была deprecated с пометкой использовать compactMap в случаях, если при обработке closure возврат может быть optional.

    @available(swift, deprecated: 4.1, renamed: "compactMap(_:)", message: "Please use compactMap(_:) for the case where closure returns an optional value")
    public func flatMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

    И отдельно появилась новая версия flatMap, которая работает.. ну как flatMap

    public func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence


  1. pqbd
    12.04.2024 10:53

    Рекурсивно...

    Извините, первый раз пишу на Swift, но вот в чём проблема рекурсии

    func flattFunction(array:[Any]) -> [Int] {
        var flattenArray = [Int]()    
        for element in array {
            if let element = element as? Int {
                flattenArray.append(element)
            } else if let element = element as? [Any] {
                let result = flattFunction(array: element)
                flattenArray += result
            }
        }    
        return flattenArray
    }
    
    func f(array:[Any]) -> [Int] {
      var tmp = array
      var r = [Int]()
      while (tmp.count > 0) {
        let  item = tmp.removeFirst()
        if (item is [Any]) {
          tmp = (item as! [Any]) + tmp
        } else {
          r.append(item as! Int)
        }
      }
      return r
    }
    
    var arr = [1] as [Any]
    for _ in 1...30024 {
        let t = arr[0]
        arr[0] = [t]
    }
    
    func testFlattFunc() {
        print(f(array: arr))
        print(flattFunction(array: arr))
    }
    
    testFlattFunc()

    https://www.programiz.com/swift/online-compiler/

    [1]
    Stack dump:
    0.	Program arguments: /usr/bin/swift-frontend -frontend -interpret /tmp/SM1XhW2TlX.swift -disable-objc-interop -color-diagnostics -new-driver-path /usr/bin/swift-driver -empty-abi-descriptor -resource-dir /usr/lib/swift -module-name SM1XhW2TlX
    1.	Swift version 5.8.1 (swift-5.8.1-RELEASE)
    2.	Compiling with the current language version
    3.	While running user code "/tmp/SM1XhW2TlX.swift"
    Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
    /usr/bin/swift-frontend(+0x59da633)[0x5890ce947633]
    /usr/bin/swift-frontend(+0x59d854e)[0x5890ce94554e]
    /usr/bin/swift-frontend(+0x59da9ba)[0x5890ce9479ba]
    /lib/x86_64-linux-gnu/libc.so.6(+0x42520)[0x7cdcd491c520]
    /usr/lib/swift/linux/libswiftCore.so(+0x3f77e1)[0x7cdcd52897e1]
    /usr/lib/swift/linux/libswiftCore.so(+0x3d542d)[0x7cdcd526742d]
    Segmentation fault

    Моя отработала, Ваша упала