2015-12-14 3 views
1

У меня есть эта рекурсивная функция, которая отлично работает в JavaScript:Как написать эту рекурсивную функцию в Swift?

var distributeSpacings = function (cols, maxSpacing) { 
    if (cols == 1) { 
     return [maxSpacing]; 
    } 

    var results = []; 

    for (var i = 0; i <= maxSpacing; i++) { 
    var subSpacings = distributeSpacings(cols - 1, maxSpacing - i); 
    for (var j = 0; j < subSpacings.length; j++) { 
     var subSpacing = subSpacings[j]; 
     results.push([i].concat(subSpacing)); 
    } 
    } 

    return results; 
} 

console.log(distributeSpacings(3, 3)); 

// prints: 
// [ [ 0, 0, 3 ], 
// [ 0, 1, 2 ], 
// [ 0, 2, 1 ], 
// [ 0, 3, 0 ], 
// [ 1, 0, 2 ], 
// [ 1, 1, 1 ], 
// [ 1, 2, 0 ], 
// [ 2, 0, 1 ], 
// [ 2, 1, 0 ], 
// [ 3, 0, 0 ] ] 

Я хочу, чтобы записать его в Swift. Безопасность типа делает это трудно - это то, что я до сих пор:

extension Array { 
    func concat(toAdd: Any) -> [Element] { 
     if let _ = toAdd as? Int { 
      return self + ([toAdd as! Element]) 
     } else { 
      return self + (toAdd as! [Element]) 
     } 
    } 
} 

func permutateSpacings (columns: Int, maxSpacing: Int) -> Any { 
    if columns == 1 { 
     return [maxSpacing] 
    } 

    var results = [Any]() 

    for (var i = 0; i <= maxSpacing; i++) { 
     var subSpacings = permutateSpacings(columns - 1, maxSpacing: maxSpacing - 1) as! [Int] // I suspect the problem is with this line 
     for (var j = 0; j < subSpacings.count; j++) { 
      let subSpacing = subSpacings[j] 
      results.append([i].concat(subSpacing)) 
     } 
    } 
    return results 
} 

print(permutateSpacings(3, maxSpacing: 3) as! [[Int]]) 
// prints: 
// Could not cast value of type 'Swift.Array<protocol<>>' (0x1175ef0d8) to 'Swift.Array<Swift.Int>' (0x1175ef028). 

ответ

1

С благодарностью солнце отыскания 1 ->i. Я получил другой результат и думал, что испортил алгоритм.


Нет необходимости для расширения массива, но это было бы правильно написано так:

extension Array { 
    func concat(toAdd: [Element]) -> [Element] { 
     return self + toAdd 
    } 
    func concat(toAdd: Element) -> [Element] { 
     return self + [toAdd] 
    } 
} 

Нет необходимости Any вообще. Тип всегда известен.

for spacing in 0...maxSpacingfor subSpacing in subSpacings Быстродействующий синтаксис для итераций.

func permutateSpacings(columns: Int, maxSpacing: Int) -> [[Int]] { 
    if columns == 1 { 
     return [[maxSpacing]] 
    } 

    var results : [[Int]] = [] // var/let : Type = Value 

    for spacing in 0...maxSpacing { 
     let subSpacings = permutateSpacings(columns - 1, maxSpacing: maxSpacing - spacing) 
     for subSpacing in subSpacings { 
      results.append(([spacing] + subSpacing)) 
     } 
    } 
    return results 
} 
3

Так мне удалось исправить вашу функцию с несколькими настройками.

Первой проблемой было то, что ваша функция вернулась Any, а не [Any]. Затем вы выбрасывали Any в [Int], и это произошло. Второй проблемой было ваше неявное литье as! [Int]. Это плохая практика, использующая ! без guard/if let (в местах, где это может привести к сбою, и здесь это, безусловно, может), и вам это действительно не нужно. Третья проблема была в строке:

var subSpacings = permutateSpacings(columns - 1, maxSpacing: maxSpacing - 1) 

Вы 1 вместо необходимости i (от вашего алгоритма JS). Работа функции ниже:

extension Array { 
    func concat(toAdd: Any) -> [Element] { 
     if let _ = toAdd as? Int { 
      return self + ([toAdd as! Element]) 
     } else { 
      return self + (toAdd as! [Element]) 
     } 
    } 
} 

func permutateSpacings (columns: Int, maxSpacing: Int) -> [Any] { 
    if columns == 1 { 
     return [maxSpacing] 
    } 

    var results = [Any]() 

    for (var i = 0; i <= maxSpacing; i++) { 
     var subSpacings = permutateSpacings(columns - 1, maxSpacing: maxSpacing - i) 
     for (var j = 0; j < subSpacings.count; j++) { 
      let subSpacing = subSpacings[j] 
      results.append([i].concat(subSpacing)) 
     } 
    } 
    return results 
} 

print(permutateSpacings(3, maxSpacing: 3))