let numbers = [1,3,4,5,5,9,0,1]
要查找第一个5
,请使用:
numbers.indexOf(5)
如何找到第二次出现?
答案 0 :(得分:5)
您可以在剩余的数组切片上执行另一个元素索引搜索,如下所示:
编辑/更新: Xcode 9•Swift 4
extension Collection where Element: Equatable {
func secondIndex(of element: Element) -> Index? {
guard let index = index(of: element) else { return nil }
return self[self.index(after: index)...].index(of: element)
}
func indexes(of element: Element) -> [Index] {
var indexes: [Index] = []
var startIndex = self.startIndex
while let index = self[startIndex...].index(of: element) {
indexes.append(index)
startIndex = self.index(after: index)
}
return indexes
}
}
测试:
let numbers = [1,3,4,5,5,9,0,1]
numbers.secondIndex(of: 5) // 4
numbers.indexes(of: 5) // [3,4]
答案 1 :(得分:1)
我认为你不能用indexOf
做到这一点。相反,您必须使用for-loop
。简写版本:
let numbers = [1,3,4,5,5,9,0,1]
var indexes = [Int]()
numbers.enumerate().forEach { if $0.element == 5 { indexes += [$0.index] } }
print(indexes) // [3, 4]
答案 2 :(得分:1)
这里是Array
的一般用途扩展,可用于在任何数组中查找某种类型的第n个元素:
extension Array where Element: Equatable {
// returns nil if there is no nth occurence
// or the index of the nth occurence if there is
func findNthIndexOf(n: Int, thing: Element) -> Int? {
guard n > 0 else { return nil }
var count = 0
for (index, item) in enumerate() where item == thing {
count += 1
if count == n {
return index
}
}
return nil
}
}
let numbers = [1,3,4,5,5,9,0]
numbers.findNthIndexOf(2, thing: 5) // returns 4
答案 3 :(得分:1)
找到第一个匹配项后,可以在数组的剩余切片上使用indexOf
来定位第二个匹配项:
let numbers = [1,3,4,5,5,9,0,1]
if let firstFive = numbers.indexOf(5) { // 3
let secondFive = numbers[firstFive+1..<numbers.count].indexOf(5) // 4
}
答案 4 :(得分:0)
编辑:根据@ davecom的评论,我在答案的底部包含了一个类似但稍微复杂的解决方案。
我在这里看到了几个很好的解决方案,特别是考虑到Swift相对较新的语言的局限性。有一种非常简洁的方法可以做到这一点,但要注意......它是相当快速和肮脏的。可能不是完美的解决方案,但它很快。 非常多才多艺(不吹嘘)。
extension Array where Element: Equatable {
func indexes(search: Element) -> [Int] {
return enumerate().reduce([Int]()) { $1.1 == search ? $0 + [$1.0] : $0 }
}
}
使用此扩展程序,您可以按如下方式访问第二个索引:
let numbers = [1, 3, 4, 5, 5, 9, 0, 1]
let indexesOf5 = numbers.indexes(5) // [3, 4]
indexesOf5[1] // 4
你已经完成了!
基本上,该方法的工作方式如下:enumerate()
将数组映射到元组,包括元素本身的每个元素的索引。在这种情况下,[1, 3, 4, 5, 5, 9, 0, 1].enumerate()
返回类型为EnumerateSequence<Array<Int>>
的集合,该集合转换为整数数组,返回[(0,1), (1,3), (2,4), (3,5), (4,5), (5,9), (6,0), (7,1)]
。
其余的工作是使用reduce
(在某些语言中称为“注入”)完成的,这是一个极其强大的工具,很多程序员都不熟悉。如果读者是那些编码器之一,我建议检查this article关于JS中函数的使用(请记住,传入的非块参数的位置是在JS中的块之后输入的,而不是在此之前看到。)
感谢阅读。
P.S。不要对这个相对简单的解决方案太过啰嗦,但如果上面显示的indexes
方法的语法有点太又快又脏,你可以试试这样的东西在方法体中,闭包的参数被扩展为更加清晰:
return enumerate().reduce([Int]()) { memo, element in
element.1 == search ? memo + [element.0] : memo
}
编辑:这是另一个选项,允许实施者扫描特定的“索引索引”(例如第二次出现5),以获得更有效的解决方案。
extension Array where Element: Equatable {
func nIndex(search: Element, n: Int) -> Int? {
let info = enumerate().reduce((count: 0, index: 0), combine: { memo, element in
memo.count < n && element.1 == search ? (count: memo.count + 1, index: element.0) : memo
})
return info.count == n ? info.index : nil
}
}
[1, 3, 4, 5, 5, 9, 0, 1].nIndex(5, n: 2) // 4
[1, 3, 4, 5, 5, 9, 0, 1].nIndex(5, n: 3) // nil
新方法仍然遍历整个数组,但由于前一种方法中缺少“数组构建”,因此效率更高。对于大多数人来说,使用8对象阵列可以忽略不计的性能。但请考虑从0到99的10,000个随机数列表:
let randomNumbers = (1...10000).map{_ in Int(rand() % 100)}
let indexes = randomNumbers.indexes(93) // count -> 100 (in my first run)
let index1 = indexes[1] // 238
// executed in 29.6603130102158 sec
let index2 = randomNumbers.nIndex(93, n: 2) // 238
// executed in 3.82625496387482 sec
可以看出,使用(非常)大数据集时,这种新方法要快得多;虽然它有点麻烦和混乱,所以根据你的应用程序,你可能更喜欢更简单的解决方案,或者完全不同的解决方案。
(再次)感谢阅读。
答案 5 :(得分:0)
extension Collection where Element: Equatable {
func nth(occurance: Int, of element: Element) -> Index? {
var level : Int = occurance
var position = self.startIndex
while let index = self[position...].index(of: element) {
level -= 1
guard level >= 0 else { return nil }
guard level != 0 else { return index }
position = self.index(after: index)
}
return nil
}
}