【问题标题】:Remove elements from string array while in a for loop whose looping condition depends on string array size在循环条件取决于字符串数组大小的 for 循环中从字符串数组中删除元素
【发布时间】:2020-07-15 16:39:22
【问题描述】:

我有一个字符串数组,我想根据 indexPath 数组中的值从其中删除元素,该数组是从表格行上的 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 循环并调用包含最终调试打印语句的方法。

【问题讨论】:

    标签: arrays swift for-loop indexpath ipados


    【解决方案1】:

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

    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{$0.section == 0}.map{$0.row})
                print("languages before filter are: \(languages)")
                languages = languages.enumerated().filter{row,_ in !rowsToRemove.contains(row)}.map{$1}
                print("languages after filter are: \(languages)")
    
                controllerData.saveLanguages(languagesToSave: languages)
                //...
            }
    

    请试一试。

    【讨论】:

      猜你喜欢
      • 2019-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多