2017-03-03 65 views
1

我正在尝试编写一个简单的手动滚动函数来压扁嵌套数组。我的代码作为一个switch语句正常工作,但不是当我递归地调用它在“我在0..arr.count”循环中。我查看传入的数组中的每个元素,并说“如果这是一个数组,调用该函数并将其传入,否则追加到输出数组”。采用通用数组的Swift函数

func flatten (input: [Any]) -> [Any] { 


    var outputArray = [Any]() 

    for i in 0..<input.count { 
     let data = input[i]; 
     (data is Array) ? outputArray += flatten(input: [data]) : outputArray.append(data) 

    } 

    return outputArray 

} 

因为我的函数参数的类型必须为[任何]的,我被迫通过“数据”变回成其为[数据]。这只是强制函数不断解压数组,并且它只是卡在循环中。有关如何避免这种情况的任何建议?

+0

可能有所帮助:http://stackoverflow.com/questions/40669193/explain-swift-iterators和http://stackoverflow.com/questions/40689128/why-are-swift-iterators-slower-than -array建设。 –

+0

也可能有帮助:[扩展具有取决于元素类型的递归属性/方法的集合](http://stackoverflow.com/q/41640321/2976878) – Hamish

+0

您是否尝试过flatmap? –

回答

0

首先,您在相当复杂的情况下使用三元运算符(?:)。如果首先修改代码以使用if语句,则出现在调用outputArray.append(data) - Generic parameter 'Element' could not be inferred时出现的编译器错误 - 显得更合理(即if语句的行)。

Generic parameter inference fails

该错误是比较容易解决 - 只需用Array<Any>取代Array,给我们这样的:

func flatten(input: [Any]) -> [Any] { 
    var outputArray = [Any]() 

    for i in 0..<input.count { 
     let data = input[i] 
     if data is Array<Any> { 
      outputArray += flatten(input: [data]) 
     } else { 
      outputArray.append(data) 
     } 
    } 

    return outputArray 
} 

此时,原来的问题仍然存在,因为这是在传递的值到flatten(input:)[data]。我们知道,由于if条件为true,因此data确实属于Array<Any>类型,因此值[data]必须是Array<Array<Any>>。相反,我们想通过data,这已经是一个数组。

你说你写[data]的原因是因为参数必须是一个数组,所以你被编译器“被迫”。实际上,编译器强迫你做的唯一事情就是传入一个参数,其类型被声明为Array<Any>。我们确信,data是使用if声明数组,但data仍然声明Any(因为它的input的元素,这是一个Array<Any>),所以编译器不知道,它是一个真正的阵列。

的解决方案是 - 而不是使用if data is Array<Any>到远暂时确定data是否是一个数组,而是立即扔的信息 - 来data转换为Array<Any>

新的if声明变为if let dataArray = data as? Array<Any>。声明data as? Array<Any>试图data转换成数组,如果成功或nil否则返回Array<Any>类型的值。然后,if let dataArray = ...声明将值存储在dataArray中,如果给定非nil值,则返回true;如果给定nil值(这称为条件绑定),则返回false

通过这样做,在true情况下if声明,我们有机会获得价值dataArrayArray<Any>类型 - 不像data,这是唯一的声明为Any。然后dataArray可以传递到flatten(input:),并且不会嵌套在另一个Array内。

func flatten(input: [Any]) -> [Any] { 
    var outputArray = [Any]() 

    for i in 0..<input.count { 
     let data = input[i] 
     if let dataArray = data as? Array<Any> { 
      outputArray += flatten(input: dataArray) 
     } else { 
      outputArray.append(data) 
     } 
    } 

    return outputArray 
} 

一对夫妇的其它注释:

Array<Any>当然相当于[Any],所以if语句可以与(通常优选的)语法来写,例如:

if let dataArray = data as? [Any] { 
    outputArray += flatten(input: dataArray) 
} 

另外,如果你只是迭代数组,就不需要经历整个for i in 0..<input.count { let data = input[i] ...的考验,就像这样:

func flatten(input: [Any]) -> [Any] { 
    var outputArray = [Any]() 

    for data in input { 
     if let dataArray = data as? [Any] { 
      outputArray += flatten(input: dataArray) 
     } else { 
      outputArray.append(data) 
     } 
    } 

    return outputArray 
}