在循环条件取决于字符串数组大小的 for 循环中从字符串数组中删除元素

Remove elements from string array while in a for loop whose looping condition depends on string array size

我有一个字符串数组,我想根据 indexPath 数组中的值从中删除元素,该数组是通过 table 行上的 2 指平移手势生成的。循环重复计数取决于字符串数组的大小,并且在每个循环中删除相关的字符串数组元素。

代码如下:

if let indexPaths = languagesTable.indexPathsForSelectedRows {
    rowCount = rowCount - (indexPaths.count)     
    controllerData.deleteWordsForLanguage(languages: languages, indexPaths: indexPaths)        
    for indexPath in indexPaths {
        print("inside 1st for loop in clearSelectedLanguages, indexPaths are: \(indexPaths)")
        print("languages.count in clearSelectedLanguages in languagesView os: \(languages.count)")
        for language in 0..<languages.count 
            print("indexPath.row == language is: \(indexPath.row == language) && indexPath.section == 0 is: \(indexPath.section == 0)")
            if indexPath.row == language && indexPath.section == 0 {
                print("inside 2nd for loop in clearSelectedLanguages in languages")
                print("languages in clearSelectedLanguages before languages.remove in languagesView are: \(languages)")
                languages.remove(at: language)
                print("languages in clearSelectedLanguages in languagesView are: \(languages)")
                }
            }
        }
    }
    controllerData.saveLanguages(languagesToSave: languages)
    languagesTable.setEditing(false, animated: true)
    languagesTable.reloadData()
    enableSort()
    enableDelete()
}

当我要求应用程序删除(按删除按钮)字符串数组的所有元素时,它会删除除一个元素之外的所有元素。我试过以不同的顺序排列字符串数组元素,它似乎不是特定于字符串元素值的,如果它是一个 3 元素数组,它总是中间元素。

我怀疑从原始大小定义所需循环数的数组中删除元素会导致第二个 for 循环出现问题。

一些调试控制台输出:

inside 1st for loop in clearSelectedLanguages, indexPaths are: [[0, 0], [0, 1], [0, 2]]
indexPath.row == language is: true && indexPath.section == 0 is: true
inside 2nd for loop in clearSelectedLanguages in languages
languages in clearSelectedLanguages in languagesView are: ["french", "spanish", "german"]
languages in clearSelectedLanguages in languagesView are: ["spanish", "german"]
indexPath.row == language is: false && indexPath.section == 0 is: true
indexPath.row == language is: false && indexPath.section == 0 is: true
inside 1st for loop in clearSelectedLanguages, indexPaths are: [[0, 0], [0, 1], [0, 2]]
indexPath.row == language is: false && indexPath.section == 0 is: true
indexPath.row == language is: true && indexPath.section == 0 is: true
inside 2nd for loop in clearSelectedLanguages in languages
languages in clearSelectedLanguages in languagesView are: ["spanish", "german"]
languages in clearSelectedLanguages in languagesView are: ["spanish"]
inside 1st for loop in clearSelectedLanguages, indexPaths are: [[0, 0], [0, 1], [0, 2]]
indexPath.row == language is: false && indexPath.section == 0 is: true
languages in saveLanguages in dataModel are: ["spanish"]

如您所见,第二组 if 条件失败,字符串数组的最后一个元素永远不会被删除。然后程序退出所有 for 循环并调用包含最终调试打印语句的方法。

使用循环按索引删除元素常常让我们感到困惑,因为目标索引会在执行循环时发生变化。

indexPaths[[0, 0], [0, 1], [0, 2]]languages["french", "spanish", "german"]

  • [0, 0] 对于 "french"
  • [0, 1] 对于 "spanish"
  • [0, 2] 对于 "german"

删除第一个indexPath[0, 0]时,可能OK:

languages in clearSelectedLanguages in languagesView are: ["french", "spanish", "german"]
languages in clearSelectedLanguages in languagesView are: ["spanish", "german"]

它删除相应的元素"french"

但是当删除第二个indexPath[0, 1]时,您可能需要仔细检查输出。

languages in clearSelectedLanguages in languagesView are: ["spanish", "german"]
languages in clearSelectedLanguages in languagesView are: ["spanish"]

它删除(最初)第三个元素 "german" 而不是第二个元素 "spanish"。因为一旦删除一个元素,数组中每个元素的索引都会改变。

因此,当您要删除第三个 indexPath [0, 2] 时,没有任何反应,因为单个元素数组 ["spanish"] 没有索引 2.

的元素

处理这种情况的一种方法是以相反的顺序从下到上删除。

    for indexPath in indexPaths.reversed() {
        //...
    }

但是双循环不是一种有效的方式,我会这样写:

        if let indexPaths = languagesTable.indexPathsForSelectedRows {
            rowCount = rowCount - (indexPaths.count)
            controllerData.deleteWordsForLanguage(languages: languages, indexPaths: indexPaths)

            print("indexPaths are: \(indexPaths)")
            let rowsToRemove = Set(indexPaths.filter{[=13=].section == 0}.map{[=13=].row})
            print("languages before filter are: \(languages)")
            languages = languages.enumerated().filter{row,_ in !rowsToRemove.contains(row)}.map{}
            print("languages after filter are: \(languages)")

            controllerData.saveLanguages(languagesToSave: languages)
            //...
        }

请尝试一下。