gpt4 book ai didi

swift - 为什么使用 .flatMap 的 Swift 函数返回 `Double` 而不是 `tuple' ?

转载 作者:行者123 更新时间:2023-11-30 12:47:34 26 4
gpt4 key购买 nike

我想使用包含 IntDouble> 的 tuple 来索引从函数返回的值。 该函数可以正常返回 Double 但是当我读取 tuple 时,我收到此错误:

'flatMap' produces '[SegmentOfResult.Iterator.Element]', not the expected contextual result type '(pitchClass: Int, frequency: Double)'

我很困惑为什么 .flatMap 返回 Double 而不是 tuple。 This linkflatMap(_:) 对于数组有意义,但我看不到与元组之间的联系来阐明这个问题。

解决这个问题的最佳方法是什么?

澄清

按照要求

tuning 是一个包含分数和小数的字符串数组

    // test pitches: rational fractions and decimal numbers   
let tuning = ["1/1", "200.0", "5/4", "500.0", "600.0", "700.0", "1000.0", "2/1"]

scaleFrequencies 是一个处理两种数字类型并返回 Double 的函数(即频率)。

我已经包含了代码初始化。

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

var notes: (pitchClass: Int, frequency: Double)
notes = tuning.flatMap(scaleFrequencies)

// print(frequency)

}



func pitchClass(pitchClass: Int, _ frequency: Double) -> Int {
return pitchClass
}

func frequency(pitchClass: Int, _ frequency: Double) -> Double {
return frequency
}



func scaleFrequencies(s: String?) -> (Int, Double) {

index += 1
var frequency: Double = 0.0
frequency = processNumerics(numericString: numericString)

return (index, frequency)
}

最佳答案

该函数目前工作正常,返回Double,并且已经给出了我需要的变量,即频率。最好不要更改它。我将创建一个新类来添加更多功能(即将频率映射到 MIDI 键盘的按键)。 感谢 Rob 和 jtbandes 的投入。

编辑

在不扩大问题空间的情况下解决这个问题更为明智。当我质疑是否需要向函数返回参数并询问如何仅使用可用参数从函数内部呈现数据时,我找到了解决方案。该解决方案解决了 accepted answer to another post 所确定的相关问题。并按照其他几篇文章的建议解包可选值,而不会导致运行时错误( here here here 。)

使用可选链接和零合并而不是强制展开来展开值。根据 these rules 有效的号码转换为频率并映射到 MIDI 键盘。无效的调音值和标有 ‘x’ 的音符字符串(由 these rules 指定)将生成 0.0 Hz 的频率。

该解决方案允许更轻松地将函数读取的可选比例值与调用其他函数时返回的频率进行比较。

例如

    Octave map

0 Optional("x")
0 : 0.0
1 Optional("35/32")
1 : 286.1534375
2 Optional("x")
2 : 0.0
3 Optional("x")
3 : 0.0
4 Optional("5/4")
4 : 327.0325
5 Optional("21/16")
5 : 343.384125
6 Optional("x")
6 : 0.0
7 Optional("3/2")
7 : 392.439
8 Optional("x")
8 : 0.0
9 Optional("x")
9 : 0.0
10 Optional("7/4")
10 : 457.8455
11 Optional("15/8")
11 : 490.54875

它还有助于读取其他 Octave 音阶的频率

    MIDI map

Octave 0
0 0 0.0
1 1 8.942294921875
2 2 0.0
3 3 0.0
4 4 10.219765625
5 5 10.73075390625
6 6 0.0
7 7 12.26371875
8 8 0.0
9 9 0.0
10 10 14.307671875
11 11 15.3296484375

Octave 1
12 0 0.0
13 1 17.88458984375
14 2 0.0
15 3 0.0
16 4 20.43953125
17 5 21.4615078125
18 6 0.0
19 7 24.5274375
20 8 0.0
21 9 0.0
22 10 28.61534375
23 11 30.659296875

Octave 2
24 0 0.0
25 1 35.7691796875
26 2 0.0

etc

Octave 9
108 0 0.0
109 1 4578.455
110 2 0.0
111 3 0.0
112 4 5232.52
113 5 5494.146
114 6 0.0
115 7 6279.024
116 8 0.0
117 9 0.0
118 10 7325.528
119 11 7848.78

Octave 10
120 0 0.0
121 1 9156.91
122 2 0.0
123 3 0.0
124 4 10465.04
125 5 10988.292
126 6 0.0

音乐应用程序的开发人员可能会发现这很有用,因为它展示了如何创建重新调整的 MIDI 映射。该解决方案使我能够解开由分数和小数组成的数字字符串,这些数字字符串指定超出标准音乐键盘范围的音阶中的音符调音。任何访问过this site的人都不会忽视它的重要性。 。

这是代码

Tuner.swift

import UIKit

class Tuner {

var tuning = [String]() // .scl
var pitchClassFrequency = Double() // .scl
let centsPerOctave: Double = 1200.0 // .scl mandated by Scala tuning file format

let formalOctave: Double = 2.0 // .kbm/.scl Double for stretched-octave tunings
var octaveMap = [Double]() // .kbm/.scl
var midiMap = [Double]() // .kbm

let sizeOfMap = 12 // .kbm
let firstMIDIKey = 0 // .kbm
let lastMIDIKey = 127 // .kbm

let referenceMIDIKey = 60 // .kbm
let referenceFrequency: Double = 261.626 // .kbm frequency of middle C

var indexMIDIKeys = Int()
var indexOctaveKeys = Int()
var currentKeyOctave = Int()
var index: Int = 0


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

// SCL file format - create frequency map of notes for one octave
print("Octave map")
print("")
let _ = tuning.flatMap(scaleToFrequencies)

// KBM file format - create frequency map of MIDI keys 0-127
print("")
print("MIDI map")
let _ = createMIDIMap()

}


func createMIDIMap() {

indexOctaveKeys = firstMIDIKey // set indexOctaveKeys to pitchClass 0
currentKeyOctave = firstMIDIKey // set currentOctave to octave 0

for indexMIDIKeys in firstMIDIKey...lastMIDIKey {
let indexOctaveKeys = indexMIDIKeys % sizeOfMap

currentKeyOctave = Int((indexMIDIKeys) / sizeOfMap)
let frequency = octaveMap[indexOctaveKeys] * 2**Double(currentKeyOctave)

// midiMap[i] = octaveMap[indexMIDIKeys] * 2**Double(currentKeyOctave)
if indexOctaveKeys == 0 {
print("")
print("Octave \(currentKeyOctave)")
}
print(indexMIDIKeys, indexOctaveKeys, frequency)
}
}


func scaleToFrequencies(s: String?) {

var frequency: Double = 0.0

// first process non-numerics.
let numericString = zapAllButNumbersSlashDotAndX(s: s)

print(index, numericString as Any) // eavesdrop on String?

// then process numerics.
frequency = (processNumericsAndMap(numericString: numericString)) / Double(2)**Double(referenceMIDIKey / sizeOfMap)
octaveMap.append(frequency)
print(index,":",frequency * 2**Double(referenceMIDIKey / sizeOfMap))
index += 1
}


func processNumericsAndMap(numericString: String?) -> Double {
guard let slashToken = ((numericString?.contains("/")) ?? nil),
let dotToken = ((numericString?.contains(".")) ?? nil),
let xToken = ((numericString?.contains("x")) ?? nil),
slashToken == false,
dotToken == true,
xToken == false
else {
guard let dotToken = ((numericString?.contains(".")) ?? nil),
let xToken = ((numericString?.contains("x")) ?? nil),
dotToken == false,
xToken == false
else {
guard let xToken = ((numericString?.contains("x")) ?? nil),
xToken == false
else {
// then it must be mapping.
let frequency = 0.0
// print("[x] \(frequency) Hz")
return frequency
}
// then process integer.
let frequency = processInteger(s: numericString)
return frequency
}
// then process fractional.
let frequency = processFractional(s: numericString)
return frequency
}
// process decimal.
let frequency = processDecimal(s: numericString)
return frequency
}


func processFractional(s: String?) -> Double {
let parts = s?.components(separatedBy: "/")
guard parts?.count == 2,
let numerator = Double((parts?[0])?.digits ?? "failNumerator"),
let dividend = Double((parts?[1])?.digits ?? "failDenominator"),
dividend != 0
else {
let frequency = 0.0
print("invalid ratio: frequency now being set to \(frequency) Hz")
return frequency
}
let frequency = referenceFrequency * (numerator / dividend)
return frequency
}


func processDecimal(s: String?) -> Double {

let parts = s?.components(separatedBy: ".")
guard parts?.count == 2,
let intervalValue = Double(s ?? "failInterval"),
let _ = Double((parts?[0])?.digits ?? "failDecimal")
else {
let frequency = 0.0
print("invalid cents value: frequency now being forced to \(frequency) Hz ")
return frequency
}
let power = intervalValue/centsPerOctave // value with explicit remainder
let frequency = referenceFrequency * (formalOctave**power)
return frequency
}


func processInteger(s: String?) -> Double {
let frequency = 0.0
print("not cents, not ratio : frequency now being set to \(frequency) Hz ")
return frequency
}


func zapAllButNumbersSlashDotAndX(s: String?) -> String? {

var mixedString = s
if mixedString != nil {
mixedString = mixedString!
}
guard var _ = mixedString?.contains("/"),
var _ = mixedString?.contains(".")
else {
let numberToken = mixedString
return numberToken
}
guard let xToken = mixedString?.contains("x"),
xToken == false
else {
let xToken = "x"
return xToken
}
let notNumberCharacters = NSCharacterSet.decimalDigits.inverted
let numericString = s?.trimmingCharacters(in: notNumberCharacters) ?? "orElse"
return numericString.stringByRemovingWhitespaces
}

}


extension String {
var stringByRemovingWhitespaces: String {
return components(separatedBy: .whitespaces).joined(separator: "")
}
}


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)
}


func pitchClass(pitchClass: Int, _ frequency: Double) -> Int {
return pitchClass
}


func frequency(pitchClass: Int, _ frequency: Double) -> Double {
return frequency
}

ViewController.swift

import UIKit

class ViewController: UIViewController {

// Hexany: 6-note scale of Erv Wilson

let tuning = ["x", "35/32", "x", "x", "5/4", "21/16", "x", "3/2", "x", "x", "7/4", "15/8"]


// 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"]


override func viewDidLoad() {
super.viewDidLoad()

_ = Tuner(tuning: tuning)


}
}

关于swift - 为什么使用 .flatMap 的 Swift 函数返回 `Double` 而不是 `tuple' ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41438058/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com