如何在Swift中创建一个闭包从字符串中提取两个整数来执行计算

时间:2016-12-24 09:40:51

标签: ios swift closures

我目前正在使用带有Swift闭包的map属性来从数组中提取线性因子,并计算跨越一个八度音阶的音乐频率列表。

    let tonic: Double   = 261.626 // middle C
    let factors         = [  1.0,   1.125, 1.25,  1.333, 1.5,   1.625,   1.875]

    let frequencies     = factors.map { $0 * tonic }
    print(frequencies)

    // [261.62599999999998, 294.32925, 327.03249999999997, 348.74745799999994, 392.43899999999996, 425.14224999999999, 490.54874999999993]

我想通过使闭包从字符串中提取两个整数并将它们分开以形成每个因子来实现此目的。字符串来自SCL tuning file,可能看起来像这样:

    //                       C      D      E      F      G      A        B 

    let ratios          = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]

可以这样做吗?

谢天谢地,是的,它可以。在三个Swift语句中,调整比率表示为自托勒密之前可以转换为精确频率之前的分数。对接受的答案稍作修改就可以得出频率列表。这是代码

import UIKit

class ViewController: UIViewController {

// Diatonic scale
let ratios = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]

// Mohajira scale
// let ratios = [ "21/20", "9/8", "6/5", "49/40", "4/3", "7/5", "3/2", "8/5", "49/30", "9/5", "11/6", "2/1"]


override func viewDidLoad() {
    super.viewDidLoad()

    _ = Tuning(ratios: ratios)

    }
}

调整课程

import UIKit

class Tuning {

    let tonic   = 261.626       // frequency of middle C (in Hertz)

    var ratios  = [String]()

init(ratios: [String]) {
    self.ratios = ratios

    let frequencies = ratios.map { s -> Double in
        let integers = s.characters.split(separator: "/").map(String.init).map({ Double($0) })
        return (integers[0]!/integers[1]!) * tonic
    }

    print("// \(frequencies)")

    }
}

以下是赫兹的频率列表,对应于全音阶音符的注释

     C           D           E           F           G           A           B     
    [261.626007, 294.329254, 327.032501, 348.834686, 392.439026, 441.493896, 490.548767]

适用于其他音阶,通常在黑白音符键盘上找不到音高 Mohajira scale created by Jacques Dudon

    //                     D                      F             G                                     C'
  let ratios = [ "21/20", "9/8", "6/5", "49/40", "4/3", "7/5", "3/2", "8/5", "49/30", "9/5", "11/6", "2/1"]

以下是产生的频率列表

    //                      D                                         F                                       G                                                                                                   C'
    // [274.70729999999998, 294.32925, 313.95119999999997, 320.49185, 348.83466666666664, 366.27639999999997, 392.43899999999996, 418.60159999999996, 427.32246666666663, 470.92679999999996, 479.64766666666662, 523.25199999999995]

声明

目前,关闭仅处理合理的规模。为了完全符合Scala SCL format,它还必须能够区分具有小数点的字符串和带小数点的字符串,并使用分数来解释后者,即对数而不是线性因子。

Thank you KangKang Adrian and Atem

3 个答案:

答案 0 :(得分:2)

let ratios = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]

let factors = ratios.map { s -> Float in
    let integers = s.characters.split(separator: "/").map(String.init).map({ Float($0) })
    return integers[0]!/integers[1]!
}

答案 1 :(得分:1)

如果我理解你的问题,你可以这样做:

func linearFactors(from string: String) -> Double? {
    let components = string.components(separatedBy: "/").flatMap { Double($0) }
    if let numerator = components.first, let denominator = components.last {
        return numerator / denominator
    }
    return nil
}

答案 2 :(得分:1)

将比率转换为double的数组

let ratios = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]

let array = ratios.flatMap { element in
    let parts = element.components(separatedBy: "/")
    guard parts.count == 2, 
          let dividend = Double(parts[0]), 
          let divisor = Double(parts[1]), 
          divisor != 0
    else {
        return nil
    }
    return parts[0] / parts[1]
}