2016-12-31 11 views
0

ここに私のprevious post on Swift optionalsに続く問題の詳細な説明があります。 here,herehere与えられたリードにSwift 3でのオプションのチェーン:なぜ1つの例はうまくいくのですか?

おかげで、私は音階の音符の周波数を計算する文字列配列から画分(高調波比用)または小数(セント)を読み取ることができています。

文字列配列の各要素は、最初に、/または2つの関数の.一方を含むかどうかを確認するためにテストされ、次に分数と小数の両方の数がこのtuning file formatで概説規則に準拠して、オプションのチェーンを使用して入力エラーを識別する。

例1および1aは、両方の形式で正しく入力されたデータがどうなるかを示しています。

  1. 画分の混合物スケールと(トップダウン)

       C  D   E  F   G   Ab  B    C’  
    let tuning = [ "1/1", "193.15686", "5/4", "503.42157", "696.57843", "25/16", "1082.89214", "2/1"] 
    

デバッグ領域の列が入力されたデータを示す小数は、行は出力周波数(L対を示しま​​す-r)。

Optional("1/1") 
    Optional("193.15686") 
    Optional("5/4") 
    Optional("503.42157") 
    Optional("696.57843") 
    Optional("25/16") 
    Optional("1082.89214") 
    Optional("2/1") 
    [261.62599999999998, 292.50676085897425, 327.03249999999997, 349.91970174951047, 391.22212058238728, 408.79062499999998, 489.02764963627084, 523.25199999999995] 

例2 & 3の両方の機能が悪い入力(すなわち、誤って入力されたデータ)にどのように反応するかを示しています。

  • 悪い画分(例えば、欠落分母は、メッセージを出力)

    Optional("1/1") 
    Optional("5/") 
    User input error - invalid fraction: frequency now being set to 0.0 Hertz 
    Optional("500.0") 
    Optional("700.0") 
    Optional("2/1") 
    [261.62599999999998, 0.0, 349.22881168708938, 391.99608729493866, 523.25199999999995] 
    
  • 悪い小数が(が報告されていない報告されている、例えばないが700後。 0 - このメッセージを生成するはずである)

    Optional("1/1") 
    Optional("5/4") 
    Optional("500.0") 
    Optional("700") 
    Optional("2/1") 
    [261.62599999999998, 327.03249999999997, 349.22881168708938, 0.0, 523.25199999999995] 
    
  • 注:オプションにnilが指定されている場合は、レポートに0.0(Hz)が表示されます。これはコードの別の場所に挿入されました(ここでコメントの文脈で説明されています)

    一言で言えば問題はありますか?分数の関数はエラーを報告しますが、10進数の関数は不正な入力を検出できません。

    どちらの関数も、オプションの連鎖を使用してガードステートメントを使用します。これは不完全な分数で機能しますが、何もせずに関数が小数点以下の入力条件を誤って報告するようにします。コードを徹底的にチェックした後、私はガード・ステートメントに設定した条件に問題があると確信しています。しかし、私はこの権利を得ることができません。誰でも私が間違っていたことを説明できますか?

    チューナー。一言で言えば迅速

    import UIKit 
    
    class Tuner { 
    
        var tuning      = [String]() 
        let tonic: Double    = 261.626 // frequency of middle C 
        var index      = -1 
        let centsPerOctave: Double  = 1200.0 // mandated by Scala tuning file format 
        let formalOctave: Double  = 2.0  // Double for stretched-octave tunings 
    
    init(tuning: [String]) { 
        self.tuning      = tuning 
    
        let frequency     = tuning.flatMap(doubleFromDecimalOrFraction) 
        print(frequency) 
    
    } 
    
    
    func doubleFromDecimalOrFraction(s: String?) -> Double { 
    
        index       += 1 
        let whichNumericStringType  = s 
        print(whichNumericStringType as Any)  // eavesdrop on String? 
    
        var possibleFrequency: Double? 
    
        // first process decimal. 
        if (whichNumericStringType?.contains("."))!    { 
         possibleFrequency   = processDecimal(s: s) 
        } 
    
        // then process fractional. 
        if (whichNumericStringType?.contains("/"))!    { 
         possibleFrequency   = processFractional(s: s) 
        } 
    
        // Insert "0.0" marker. Remove when processDecimal works 
        let noteFrequency    = possibleFrequency 
        let zeroFrequency    = 0.0 
        // when noteFrequency? is nil, possibleFrequency is set to zeroFrequency 
        let frequency     = noteFrequency ?? zeroFrequency 
    
        return frequency // TO DO let note: (index: Int, frequency: Double) 
    
        } 
    
    
    func processFractional(s: String?) -> Double? { 
    
        var fractionArray    = s?.components(separatedBy: "/") 
    
        guard let numerator    = Double((fractionArray?[0])!.digits), 
         let denominator    = Double((fractionArray?[1])!.digits), 
         numerator     > 0, 
         denominator     != 0, 
         fractionArray?.count  == 2 
         else 
        { 
         let possibleFrequency  = 0.0 
         print("User input error - invalid fraction: frequency now being set to \(possibleFrequency) Hertz ") 
         return possibleFrequency 
         } 
        let possibleFrequency   = tonic * (numerator/denominator) 
        return possibleFrequency 
         } 
    
    
    func processDecimal(s: String?) -> Double?  { 
    
        let decimalArray    = s?.components(separatedBy: ".") 
        guard let _      = s, 
         decimalArray?.count   == 2 
         else 
        { 
         let denominator    = 1 
         let possibleFrequency  = 0.0 
         print("User input error (value read as \(s!.digits)/\(denominator) - see SCL format, http://www.huygens-fokker.org/scala/scl_format.html): frequency now being forced to \(possibleFrequency) Hertz ") 
         return possibleFrequency 
         } 
        let power      = Double(s!)!/centsPerOctave 
        let possibleFrequency   = tonic * (formalOctave**power) 
        return possibleFrequency 
         } 
        } 
    
    
    extension String { 
    
        var digits: String { 
        return components(separatedBy: CharacterSet.decimalDigits.inverted).joined() 
         } 
        } 
    
    
    precedencegroup Exponentiative { 
    
        associativity: left 
        higherThan: MultiplicationPrecedence 
    
        } 
    
    
    infix operator ** : Exponentiative 
    
    func ** (num: Double, power: Double) -> Double{ 
        return pow(num, power) 
        } 
    

    ViewController.swift

    import UIKit 
    
    class ViewController: UIViewController { 
    
        // test pitches: rational fractions and decimal numbers (currently 'good') 
        let tuning = ["1/1", "5/4", "500.0", "700.0", "2/1"] 
    
        // Diatonic scale: rational fractions 
        //  let tuning = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8", "2/1"] 
    
        // Mohajira: rational fractions 
        // let tuning = [ "21/20", "9/8", "6/5", "49/40", "4/3", "7/5", "3/2", "8/5", "49/30", "9/5", "11/6", "2/1"] 
    
        // Diatonic scale: 12-tET 
        // let tuning = [ "0.0", "200.0", "400.0", "500", "700.0", "900.0", "1100.0", "1200.0"] 
    
        // Diatonic scale: mixed 12-tET and rational fractions 
        // let tuning = [ "0.0", "9/8", "400.0", "4/3", "700.0", "27/16", "1100.0", "2/1"] 
    
        // Diatonic scale: 19-tET 
        //  let tuning = [ "0.0", "189.48", "315.8", "505.28", "694.76", "884.24", "1073.72", "1200.0"] 
    
        // Diatonic 1/4-comma meantone scale. Pietro Aaron's temperament (1523) : mixed cents and rational fractions 
        // let tuning = [ "1/1", "193.15686", "5/4", "503.42157", "696.57843", "25/16", "1082.89214", "2/1"] 
    
    override func viewDidLoad() { 
        super.viewDidLoad() 
    
        _ = Tuner(tuning: tuning) 
    
        } 
    } 
    
    +0

    string = "700"のときprocessDecimal funcをデバッグしましたか?私はdecimalArray.countが何であるか知っていることに興味があります。 –

    +1

    上に明示的に強制アンラッピング( '!')がたくさんあります。 'processFractional':これは実行時のクラッシュを引き起こす可能性があるため、一般的に避けてください。例えば。 'processFractional(...)'、 'Double((fractionArray?[0])!. digits)'の 'guard 'のために、オプションの連鎖と' nil'合体演算子で安全にすることができます。 'Double((fractionArray?[0])?digits ??" failMe ")'。 – dfri

    +0

    3つのすべての回答は、以前の質問を解決するにはhttp://stackoverflow.com/a/41337042/2348597、http://stackoverflow.com/a/41337068/2348597、http://stackoverflow.com/a/41359262/2348597強制アンラッピングなしのタスク。 –

    答えて

    3

    問題?分数の関数はエラーを報告しますが、10進数の関数は不正な入力を検出できません。

    10進数の関数は「悪い」入力を検出します。ただし、"700"には"."が含まれておらず、文字列に"."が含まれている場合は、processDecimal(s:)のみを呼び出します。文字列に"."が含まれておらず、"/"も含まれていない場合、doubleFromDecimalOrFraction(s:)は文字列を解析する関数を呼び出しません。

    +0

    良い点、それを逃した。 –

    +0

    @Martin R、@robmayoff、これは、私が小数ではなく分数でこのような問題を抱えていた理由です。私は '' ''や ''/''を使わずに文字列を処理するための第3の関数を導入する方法を知っていますか、あるいは両方の関数のリワークされたバージョンを "強制アンラッピングなし" )? – Greg

    +0

    @rob mayor、accepted。あなたはそれを指摘しました!私は来年、私のソリューションの最初のものを使って投稿を編集します! – Greg

    関連する問題