【问题标题】:How to get the index of an item in a 2D array?如何获取二维数组中项目的索引?
【发布时间】:2023-05-31 11:50:01
【问题描述】:

如果我有一个数组:

let array = [
        ["Hamburger", "Nachos", "Lasagne"],
        ["Tomatoes", "Apples", "Oranges"],
        ["Soda", "Juice", "Water"]
    ]    

例如“Apples”的索引是多少?有没有办法以编程方式获取它?

【问题讨论】:

  • 你的意思是,一个函数 getIndexFor("Oranges") 会返回一个元组 (1, 2)?

标签: arrays swift


【解决方案1】:

您可以使用firstIndex(where:) 并使用firstIndex(of:) 找到它的子索引:

let array = [
    ["Hamburger", "Nachos", "Lasagne"],
    ["Tomatoes", "Apples", "Oranges"],
    ["Soda", "Juice", "Water"]
]

let query = "Apples"
if let index = array.firstIndex(where: {$0.contains(query)}),
    let subIndex = array[index].firstIndex(of: query) {
    print(array[index][subIndex])  // Apples

}

作为扩展:

extension Collection where Element: Collection, Element.Element: Equatable {
    func firstIndexAndSubIndex(of element: Element.Element) -> (index: Index, subIndex: Element.Index)? {
        if let index = firstIndex(where: {$0.contains(element)}),
            let subIndex = self[index].firstIndex(of: element) {
            return (index,subIndex)
        }
        return nil
    }
}

用法:

let array = [
    ["Hamburger", "Nachos", "Lasagne"],
    ["Tomatoes", "Apples", "Oranges"],
    ["Soda", "Juice", "Water"]
]
let query = "Soda"
if let indexes = array.firstIndexAndSubIndex(of: query) {
    print(indexes)   // "(index: 2, subIndex: 0)\n"
}

这也适用于从字符串数组中查找字符的索引:

let array = ["Hamburger", "Nachos", "Lasagne"]
let query: Character = "h"
if let indices = array.indexAndSubIndex(of: query) {
    print(indices)   // "(index: 1, subIndex: Swift.String.Index(_rawBits: 196865))\n"
    array[indices.index][indices.subIndex]  // "h"
}

【讨论】:

    【解决方案2】:

    作为扩展的另一个选项。函数tupleIndex(of:)返回一个元组(Int, Int)?

    let array = [
        ["Hamburger", "Nachos", "Lasagne"],
        ["Tomatoes", "Apples", "Oranges"],
        ["Soda", "Juice", "Water"]
    ]
    
    extension Collection where
        Element: Collection,
        Element.Element: Equatable,
        Element.Index == Int {
    
        func tupleIndex(of elementToFind: Element.Element) -> (Int, Int)? {
            for (firstIndex, element) in self.enumerated() {
                if let secondIndex = element.index(of: elementToFind) {
                    return (firstIndex, secondIndex)
                }
            }
            return nil
        }
    }
    

    你可以这样使用它:

    print(array.tupleIndex(of: "Apples")) //prints Optional((1, 1))
    

    【讨论】:

    • 在 Swift 4 中你可以简化约束,因为 Element == Iterator.Element.
    • 最好添加一个约束 Element.Index == Int 而不是条件转换 as? Int。 – 使用您的方法 ["abc", "def"].tupleIndex(of: "b") 编译,但返回 nil。
    • 你是对的。我错过了那个案子。无论如何,我对有条件的演员不满意,所以谢谢你的建议。我将编辑我的答案。
    【解决方案3】:

    它不优雅但易于阅读

    func getIndices(arr: [[String]], word: String) -> (Int, Int)? {
      for i in 0..<arr.count {
        let subArr = arr[i]
        if let index = subArr.index(of: word) {
            return (i, index)
        }
      }
      return nil
    }
    let result = getIndices(arr: array, word: "Apples"))
    

    【讨论】:

      【解决方案4】:
      let array = [
              ["Hamburger", "Nachos", "Lasagne"],
              ["Tomatoes", "Apples", "Oranges"],
              ["Soda", "Juice", "Water"]
      ]
      
      for arr in array {
      
        let answer = arr.indexOf("Apples")
        if answer {
          break
        }
      print(answer)
      }
      

      【讨论】:

      • indexOf 已重命名为 index(of:)
      • 顺便说一句,它不是布尔值。你不能在条件 if 中使用它。
      • 如果你打破循环,它将永远不会被打印
      • 如果你不枚举数组你就不会知道外部索引。
      • 同意@LeoDabus。你想达到什么目的?