Swift - 如何获取数组中筛选项目的索引

41
let items: [String] = ["A", "B", "A", "C", "A", "D"]

items.whatFunction("A") // -> [0, 2, 4]
items.whatFunction("B") // -> [1]

Swift 3支持类似whatFunction(_: Element)的函数吗?

如果不支持,最有效的逻辑是什么?


你可以通过以下方式找到 "a" 的索引:let indexOfA = arr.index(of: "a")。 - Bhupat Bheda
@BhupatBheda 谢谢,但是 index(of: Element) 只返回 Int?。我需要的函数应该返回 [Int]? - Byoth
9个回答

50

你可以直接过滤数组的indices,这样可以避免额外的map操作。

let items = ["A", "B", "A", "C", "A", "D"]
let filteredIndices = items.indices.filter {items[$0] == "A"}

或者作为Array的扩展:

extension Array where Element: Equatable {

    func whatFunction(_ value :  Element) -> [Int] {
        return self.indices.filter {self[$0] == value}
    }

}

items.whatFunction("A") // -> [0, 2, 4]
items.whatFunction("B") // -> [1]

或者更加通用

extension Collection where Element: Equatable {

    func whatFunction(_ value :  Element) -> [Index] {
        return self.indices.filter {self[$0] == value}
    }

}

你可以扩展Collection,因为实现并没有使用任何特定于数组的内容。 - Tim Vermeulen
@vadian,您是否愿意查看https://stackoverflow.com/q/54088250/4601170并帮助我? - Bhavin Bhadani

36

你可以为数组创建自己的扩展。

extension Array where Element: Equatable {
    func indexes(of element: Element) -> [Int] {
        return self.enumerated().filter({ element == $0.element }).map({ $0.offset })
    }
}

你可以直接这样调用它

items.indexes(of: "A") // [0, 2, 4]
items.indexes(of: "B") // [1]

太棒了!谢谢! - Byoth
这是一个非常棒的答案! - jlstr
嗨,它返回了空值吗? - famfamfam
使用.enumerated()是一个坏主意,因为它不保证是索引,正如苹果文档所述:“当您枚举集合时,每个对的整数部分是枚举的计数器,但不一定是配对值的索引。” - zero3nna

33

通过如下步骤可以实现:

  1. enumerated() - 添加索引;
  2. filter() - 过滤不必要的项目;
  3. map() - 处理索引。

示例(适用于 Swift 3 - Swift 4.x):

let items: [String] = ["A", "B", "A", "C", "A", "D"]  
print(items.enumerated().filter({ $0.element == "A" }).map({ $0.offset })) // -> [0, 2, 4]

另一种方法是使用 flatMap,它允许您在一个闭包中检查元素并返回索引。

示例(适用于 Swift 3 - Swift 4.0):


print(items.enumerated().flatMap { $0.element == "A" ? $0.offset : nil }) // -> [0, 2, 4]

但自从Swift 4.1以来,可以返回非零对象的flatMap已被弃用,而应该使用compactMap

例如(可在Swift 4.1以上版本中使用):

print(items.enumerated().compactMap { $0.element == "A" ? $0.offset : nil }) // -> [0, 2, 4]

最干净、最省内存的方法是通过迭代数组 indices 并检查当前索引处的数组元素是否等于所需元素。

示例(适用于 Swift 3 - Swift 5.x):


print(items.indices.filter({ items[$0] == "A" })) // -> [0, 2, 4]

1
请注意,您也可以将filter和map组合成flatMap,就像Julien所做的那样,但在答案中提供更多细节也是很好的。 - David Berry
只是另一种方法而已。就我个人而言,如果筛选和映射具有不同的基础,我通常更喜欢将它们拆分为单独的步骤,就像这样。另一方面,如果想要在同一属性上进行筛选和映射,则 flatMap 更合适。 - David Berry
1
哇,太棒了! - Osman Tüfekçi
1
感谢您提供的索引建议。这正是我需要清理笨拙代码的东西。 - John
1
谢谢,非常好的答案。 - musakokcen
显示剩余2条评论

9
在 Swift 3 和 Swift 4 中,您可以这样做:
let items: [String] = ["A", "B", "A", "C", "A", "D"]

extension Array where Element: Equatable {

    func indexes(of item: Element) -> [Int]  {
        return enumerated().compactMap { $0.element == item ? $0.offset : nil }
    }
}

items.indexes(of: "A")

我希望我的回答对您有所帮助。


4

您可以这样使用:

 let items: [String] = ["A", "B", "A", "C", "A", "D"]

        let indexes = items.enumerated().filter {
            $0.element == "A"
            }.map{$0.offset}

        print(indexes)

1

只需复制粘贴

extension Array {
  func whatFunction(_ ids :  String) -> [Int] {

    var mutableArr = [Int]()
    for i in 0..<self.count {
        if ((self[i] as! String) == ids) {
            mutableArr.append(i)
        }
    }
        return mutableArr 
  }

}

1
您可以使用下面的代码:
var firstArray = ["k","d","r","r","p","k","b","p","k","k"]
var secondArray = ["k","d","r","s","d","r","b","c"]

let filterArray = firstArray.filter { secondArray.contains($0) }
let filterArray1 = firstArray.filter { !secondArray.contains($0) }
let filterIndex = firstArray.enumerated().filter { $0.element == "k" }.map { $0.offset }
print(filterArray) --> // ["k", "d", "r", "r", "k", "b", "k", "k"]
print(filterArray1) --> // ["p", "p"]
print(filterIndex) --> // [0, 5, 8, 9]

0

这也可以是一种方式

// MARK: - ZIP: Dictionary like

let words = ["One", "Two", "Three", "Four"]
let numbers = 1...words.count

for (word, number) in zip(words, numbers) {
    print("\n\(word): \(number)")
}

-1
例如,查找在inds1数组中的p_last值的索引:(Swift 4+)
let p_last = [51,42]
let inds1 = [1,3,51,42,4]
let idx1 = Array(inds1.filter{ p_last.contains($0) }.indices)

idx1 = [0,1]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接