在Swift中展平数组数组


143

在Swift中flatten,Scala,Xtend,Groovy,Ruby和co中有对应的产品吗?

var aofa = [[1,2,3],[4],[5,6,7,8,9]]
aofa.flatten() // shall deliver [1,2,3,4,5,6,7,8,9] 

我当然可以使用reduce,但是有点烂

var flattened = aofa.reduce(Int[]()){
    a,i in var b : Int[] = a
    b.extend(i)
    return b
}

就像使用数组的add对象吗?
范范an 2014年

我还没有研究Swift本身,但是在Haskell和F#中,它是`concat`-所以也许看起来像这样?-我很肯定这是存在的地方(大多数FP语言都知道单子,这是List的约束)
Carsten 2014年

是的,在haskell中它实际上称为concat。
Christian Dietrich 2014年


Answers:


436

迅捷> = 3.0

reduce

let numbers = [[1,2,3],[4],[5,6,7,8,9]]
let reduced = numbers.reduce([], +)

flatMap

let numbers = [[1,2,3],[4],[5,6,7,8,9]]
let flattened = numbers.flatMap { $0 }

joined

let numbers = [[1,2,3],[4],[5,6,7,8,9]]
let joined = Array(numbers.joined())

在此处输入图片说明


3
为了更笼统地说明这一点,flatMap从Swift 1.2开始可用。
Mick MacCallum 2015年

3
joined(正式称为flatten)和之间有什么区别flatMap?只是在flatMap加入时它还可以映射/转换事物。但在此示例中,我们确实不需要,即返回$0
亲爱的

6
@Dschee flatMap任一弄平的2D阵列成一维数组删除nil值,而不是两者。它根据第一级数组Element是数组还是可选数组来确定要执行的操作,因此,如果将其传递给可选数组(例如[[Int?]]的2D数组,它将选择将其展平为1D (例如[Int?]。要将其展平至一维并删除第二级钉子,您必须这样做array.flatMap { $0 }.flatMap { $0 }。换句话说,尺寸平整等于,Array(array.joined())并且去除nil的“平整”等于array.filter{ $0 != nil }.map{ $0! }
斯利普·汤普森

1
@Warpling flatMap仍适用于问题中所述的用途(将2D数组展平为1D)。compactMap明确地是用于nil从序列中删除项目,就像flatMap曾经的变体一样。
吉姆·多维

1
@mohamadrezakoohkan是正确的。由于您的数组是type [[Any]]flatMap只需将其转换为[Any]([1、2、3、4,[5、6],7、8、9])类型。如果我们flatMap再次申请,我们将采取“任何行动?类型,编译器不再知道它是简单值还是数组本身。
andreschneider

31

在Swift标准库中,joined为所有符合Sequence协议的类型(或flattenSequenceTypeSwift 3之前的版本)实现了函数,其中包括Array

let numbers = [[1,2,3],[4],[5,6,7,8,9]]
let flattened = Array(numbers.joined())

在某些情况下,使用of joined()可能是有益的,因为它返回一个惰性集合而不是一个新数组,但是在传递给Array()初始化程序时总是可以转换为数组,如上例所示。


@chrisco能否请您详细说明我的答案是错误的,“简单正确答案”的标准是什么?您能否说明删除答案对问题有何影响?
Max Desiatov

尝试先运行您的代码段-您认为它能做什么?它实际上是做什么的?最初的问题是什么?您的答案正确吗?如果没有,最好将其删除以提高本文的清晰度。我做了同样的事情,但我自己的答案不正确。
克里斯·康诺佛

1
@chrisco非常感谢您的建议,但我会先运行摘要,然后再将其发布到任何地方。我的回答是正确的,因为它返回的结果与OP请求的结果完全相同,并且使用的代码更少。我承认我的原始答案是返回惰性集合而不是数组,尽管问题中对此没有限制。我仍然认为删除正确答案不会以任何方式提高问题的质量。
Max Desiatov

这就是我的观点-测试/打印输出时,您会得到一个数组数组:FlattenBidirectionalCollection<Array<Array<Int>>>(_base: [[1, 2, 3], [4], [5, 6, 7, 8, 9]]))。您的观点是正确的,尽管您可以像访问平面数组一样访问它,所以似乎CustomStringConvertable实现方式具有误导性。您的代码段曾经并且仍然缺少测试。
克里斯·康诺弗

1
自swift 3.0起,flatten()已重命名为joined()
Xcoder先生17年

16

斯威夫特4.x / 5.x

只是增加了数组的复杂度,如果存在包含数组数组的数组,则flatMap实际上会失败。

假设数组是

var array:[Any] = [1,2,[[3,4],[5,6,[7]]],8]

什么flatMapcompactMap回报是:

array.compactMap({$0})

//Output
[1, 2, [[3, 4], [5, 6, [7]]], 8]

为了解决这个问题,我们可以使用简单的for循环逻辑+递归

func flattenedArray(array:[Any]) -> [Int] {
    var myArray = [Int]()
    for element in array {
        if let element = element as? Int {
            myArray.append(element)
        }
        if let element = element as? [Any] {
            let result = flattenedArray(array: element)
            for i in result {
                myArray.append(i)
            }

        }
    }
    return myArray
}

所以用给定的数组调用这个函数

flattenedArray(array: array)

结果是:

[1, 2, 3, 4, 5, 6, 7, 8]

考虑到Int此处的情况,此函数将有助于展平任何类型的数组

游乐场输出: 在此处输入图片说明




2

斯威夫特4.2

我在下面写了一个简单的数组扩展。您可以用来展平包含另一个数组或元素的数组。与joined()方法不同。

public extension Array {
    public func flatten() -> [Element] {
        return Array.flatten(0, self)
    }

    public static func flatten<Element>(_ index: Int, _ toFlat: [Element]) -> [Element] {
        guard index < toFlat.count else { return [] }

        var flatten: [Element] = []

        if let itemArr = toFlat[index] as? [Element] {
            flatten = flatten + itemArr.flatten()
        } else {
            flatten.append(toFlat[index])
        }

        return flatten + Array.flatten(index + 1, toFlat)
    }
}

用法:

let numbers: [Any] = [1, [2, "3"], 4, ["5", 6, 7], "8", [9, 10]]

numbers.flatten()

1

的另一个更通用的实现reduce

let numbers = [[1,2,3],[4],[5,6,7,8,9]]
let reduced = reduce(numbers,[],+)

这可以完成相同的操作,但可以使您更深入地了解正在发生的事情reduce

根据Apple的文档,

func reduce<S : SequenceType, U>(sequence: S, initial: U, combine: (U, S.Generator.Element) -> U) -> U

描述

返回重复调用的结果,并结合初始化为initial的累加值和sequence的每个元素。


使用您的代码,我得到:Use of unresolved identifier 'reduce'
Jason Moore

1

修改了@RahmiBozdag的答案:1.公共扩展名中的方法是公共的。2.删除了额外的方法,因为开始索引将始终为零。3.由于在方法T内部始终为[Any?],因此我没有找到将compactMap放入nil和optionals的方法,欢迎任何建议。

 let array = [[[1, 2, 3], 4], 5, [6, [9], 10], 11, nil] as [Any?]

 public extension Array {

 func flatten<T>(_ index: Int = 0) -> [T] {
        guard index < self.count else { 
            return [] 
        }

        var flatten: [T] = []

        if let itemArr = self[index] as? [T] {
            flatten += itemArr.flatten()
        } else if let element = self[index] as? T {
            flatten.append(element)
        }
        return flatten + self.flatten(index + 1)
   }

}

let result: [Any] = array.flatten().compactMap { $0 }
print(result)
//[1, 2, 3, 4, 5, 6, 9, 10, 11]

0

您可以使用以下方法展平嵌套数组:

var arrays = [1, 2, 3, 4, 5, [12, 22, 32], [[1, 2, 3], 1, 3, 4, [[[777, 888, 8999]]]]] as [Any]

func flatten(_ array: [Any]) -> [Any] {

    return array.reduce([Any]()) { result, current in
        switch current {
        case(let arrayOfAny as [Any]):
            return result + flatten(arrayOfAny)
        default:
            return result + [current]
        }
    }
}

let result = flatten(arrays)

print(result)

/// [1, 2, 3, 4, 5, 12, 22, 32, 1, 2, 3, 1, 3, 4, 777, 888, 8999]

0

Apple Swift版本5.1.2(swiftlang-1100.0.278 clang-1100.0.33.9)
目标:x86_64-apple-darwin19.2.0

屏幕截图

let optionalNumbers = [[1, 2, 3, nil], nil, [4], [5, 6, 7, 8, 9]]
print(optionalNumbers.compactMap { $0 }) // [[Optional(1), Optional(2), Optional(3), nil], [Optional(4)], [Optional(5), Optional(6), Optional(7), Optional(8), Optional(9)]]
print(optionalNumbers.compactMap { $0 }.reduce([], +).map { $0 as? Int ?? nil }.compactMap{ $0 }) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(optionalNumbers.compactMap { $0 }.flatMap { $0 }.map { $0 as? Int ?? nil }.compactMap{ $0 }) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(Array(optionalNumbers.compactMap { $0 }.joined()).map { $0 as? Int ?? nil }.compactMap{ $0 }) // [1, 2, 3, 4, 5, 6, 7, 8, 9]

let nonOptionalNumbers = [[1, 2, 3], [4], [5, 6, 7, 8, 9]]
print(nonOptionalNumbers.compactMap { $0 }) // [[1, 2, 3], [4], [5, 6, 7, 8, 9]]
print(nonOptionalNumbers.reduce([], +)) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(nonOptionalNumbers.flatMap { $0 }) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(Array(nonOptionalNumbers.joined())) // [1, 2, 3, 4, 5, 6, 7, 8, 9]

0

迅捷5.1

public extension Array where Element: Collection {

    func flatten() -> [Element.Element] {
        return reduce([], +)
    }
}

如果您还希望将其用于Dictionary值:

public extension Dictionary.Values where Value : Collection {
    func flatten() -> [Value.Element]{
         return self.reduce([], +)
    }
}


-1

矩阵是[[myDTO]]?

在Swift 5中,您可以使用此= Array(self.matrix!.joined())


-2
func convert(){
    let arr = [[1,2,3],[4],[5,6,7,8,9]]
    print("Old Arr = ",arr)
    var newArr = [Int]()
    for i in arr{
        for j in i{
            newArr.append(j)
        }
    }
    print("New Arr = ",newArr)
}

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.