SWIFT 中的元组数组作为函数的参数

Tuple array in SWIFT as a parameter of function

我需要将元组数组作为参数传递给从数组中选择随机元组的函数,同时考虑两个其他参数)这个函数 returns 索引,然后我将使用它来播放这个随机文件。而这个函数在class fileManager()

class fileManager  {
    var drums = [
        ("drum", "drum", 8, 2, false, 153, "C", 1),
        ("drum", "drum2", 6, 3, false, 153, "C", 1),
        ("drum", "drum3", 8, 2, false, 153, "C", 1),
        ("drum", "drum4", 4, 2, false, 153, "C", 1),
        ("drum", "drum5", 8, 1, false, 153, "C", 1)  ]

    var piano = [
        ("piano", "piano", 8, 2, false, 153, "C", 1),
        ("piano", "piano2", 8, 3, false, 153, "C", 1),
        ("piano", "piano3", 8, 1, false, 153, "C", 1)
    ]

    //instrumentArray will be any instrument, Strength - we need to find, KeyNote - we need to find in Array.

    func randomizeTheNextInstrument (instrumentArrayInput: [(String,String,Int,Int,Bool,Int,String, Int)], Strength: Int , KeyNote: String) -> Int {
        var instrumentArray = instrumentArrayInput
        var indexInstrument: Int!
        for index in 0...instrumentArray.count {
            if instrumentArray[index].4 == true { //check if played
                instrumentArray.removeAtIndex(index)
            }
            if instrumentArray[index].6 != KeyNote { // check keyNote
                instrumentArray.removeAtIndex(index)
            }
            if instrumentArray[index].3 != Strength { // check strength
                instrumentArray.removeAtIndex(index)
            }
        }

        var indexToChoose: Int = Int(arc4random_uniform(UInt32(instrumentArray.count)))
        for index in 0...instrumentArrayInput.count {
            if instrumentArrayInput[index].1 == instrumentArray[indexToChoose].1 { // finds what one in ArrayInpu equals the randomized one in Array that chosen
                indexInstrument = index
            }
        }
        return indexInstrument
    }
}

但是当我通过这样做从另一个 class 调用函数时。

indexToPlay = Int(fileManager().randomizeTheNextInstrument(fileManager().drums, Strength: drumStrength, KeyNote: "C"))

它给我致命错误:“数组索引超出范围 (lldb)” 它告诉我数组 instrumentArrayInput 有 5 个值,但值为 'none',instrumentArray 有 3 个值,但值为 'none'。接下来看起来很奇怪的是 indexToChoose = 140734791422096。而且它还写了我 EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, sub code=0x0) 的字符串:

if instrumentArray[index].4 == true { 

我做错了什么?

这个:

for index in 0...instrumentArray.count {

应该是:

for index in 0..<instrumentArray.count {

由于数组是零索引的,因此最后一个有效索引比数组中的项目数少一。

Anthony 实际上指出了您的函数的其他几个问题,所有这些问题都可以通过使用内置的过滤器函数来解决:

instrumentArray = instrumentArrayInput.filter {
    return ![=12=].4 && [=12=].6 == KeyNote && [=12=].3 == Strength
}

替换整个 for 循环。

为了解决更多的问题,我会选择这样的方法,尽管有更多的更改需要推荐(比如使用结构或 class 而不是元组):

class FileManager  {
    typealias Instrument = (String,String,Int,Int,Bool,Int,String, Int)

    var drums : [Instrument] = [
        ("drum", "drum", 8, 2, false, 153, "C", 1),
        ("drum", "drum2", 6, 3, false, 153, "C", 1),
        ("drum", "drum3", 8, 2, false, 153, "C", 1),
        ("drum", "drum4", 4, 2, false, 153, "C", 1),
        ("drum", "drum5", 8, 1, false, 153, "C", 1)  
    ]

    var piano : [Instrument] = [
        ("piano", "piano", 8, 2, false, 153, "C", 1),
        ("piano", "piano2", 8, 3, false, 153, "C", 1),
        ("piano", "piano3", 8, 1, false, 153, "C", 1)
    ]

    func randomizeTheNextInstrument(instrumentArrayInput: [Instrument], Strength: Int, KeyNote: String) -> Int? {
        let instrumentArray = instrumentArrayInput.filter {
            return ![=13=].4 && [=13=].6 == KeyNote && [=13=].3 == Strength
        }

        if instrumentArray.count <= 0 {
            return nil
        }

        let indexToChoose: Int = Int(arc4random_uniform(UInt32(instrumentArray.count - 1)))
        let name = instrumentArray[indexToChoose].1

        for index in 0 ..< instrumentArrayInput.count {
            if name == instrumentArrayInput[index].1 {
                return index
            }
        }

        return nil
    }
}

let fileManager = FileManager()

if let indexToPlay = fileManager.randomizeTheNextInstrument(fileManager.drums, Strength: 3, KeyNote: "C") {
    println("\(fileManager.drums[indexToPlay])")
    fileManager.drums[indexToPlay].4 = true
}

if let indexToPlay = fileManager.randomizeTheNextInstrument(fileManager.drums, Strength: 3, KeyNote: "C") {
    println("\(fileManager.drums[indexToPlay])")
    fileManager.drums[indexToPlay].4 = true
}

在循环中,您正在从数组中删除元素,因此它的长度减少了。 而且,有3个独立的if语句,可以导致在同一次迭代中最多移除3个元素。我会在每个 if 主体中添加一个 break (以跳过当前迭代并移动到下一个),或者将它们重新组织为 if/else if/else.

然而,为了修复异常,而不是从数组中删除元素,我建议添加元素以保留在第二个数组中,或者只保留它们的索引。

最后,注意循环错了,应该是for index in 0..<instrumentArray.count而不是for index in 0...instrumentArray.count


更新

如果你还需要保持原来的从数组中删除元素的想法,那么你应该修改循环以倒序遍历它,并使用if/elseif而不是独立的if。例如:

for var index = instrumentArray.count - 1; index >= 0; --index {
    if instrumentArray[index].4 == true { //check if played
        instrumentArray.removeAtIndex(index)
    } else if instrumentArray[index].6 != KeyNote { // check keyNote
        instrumentArray.removeAtIndex(index)
    } else if instrumentArray[index].3 != Strength { // check strength
        instrumentArray.removeAtIndex(index)
    }
}

需要倒序循环,因为当一个元素被移除时,它之后的所有元素都会向后移动一个位置,而它之前的所有元素都不会受到影响。这样您就可以确保所有仍待处理的元素的索引都不会更改。