如何从 Swift ArraySlice 中获取第 i 个元素?
How do I fetch the i'th element from a Swift ArraySlice?
下面我试图获取 ArraySlice
draggignFan
的第 i 个元素。代码构建良好(没有警告)但程序在运行时死于我尝试像普通数组一样索引切片的行:
var draggingFan : ArraySlice<Card>?
...
if let draggingFan = draggingFan {
for i in 1 ..< draggingFan.count {
let card = draggingFan[i] // EXECUTION ERROR HERE
...
}
}
根据 the docs 有一个 first
和 last
方法(我在别处使用没有问题)。那么如何在 Swift 中索引一个 ArraySlice
呢? (注意:我故意跳过切片中的第 0 个索引——其他地方需要)。
您遇到此问题的原因是切片保留了您从中获取的序列的原始索引号。因此,元素 1 不在此切片中。
例如,考虑以下代码:
let arr = [1,2,3,4,5,6,7,8,9]
let slice = arr[2...5]
现在 slice[1]
是什么?它不是 4
,即使那是切片中的第二个东西。它是 2
,因为切片仍然指向原始数组。换句话说,slice[1]
超出了切片的范围!这就是您收到运行时错误的原因。
怎么办?那么,切片的实际索引是它的 indices
。 那个 是你想要循环的。但是......你不想要切片指向的第一个元素。所以你需要推进你要迭代的范围的 startIndex
。因此:
if let draggingFan = draggingFan {
var ixs = draggingFan.indices
ixs.startIndex = ixs.startIndex.advancedBy(1)
for i in ixs {
// ... now your code will work ...
}
}
但是,在我看来,根本没有必要为切片建立索引,您也不应该这样做。您应该循环遍历 切片本身 ,而不是遍历其索引。你有这个:
for i in 1 ..< draggingFan.count
但这很像在说
for aCard in draggingFan
...除了您想删除切片的第一个元素。那就放下吧!这么说:
for aCard in draggingFan.dropFirst()
要了解这是否有效,请在 playground 中尝试:
let arr = [1,2,3,4,5,6,7,8,9]
let slice = arr[2...5]
for anInt in slice.dropFirst() {
print(anInt) // 4, 5, 6
}
如您所见,我们正在循环遍历所需的元素,根本没有参考索引号。
迭代切片中的元素:
draggingFan?.forEach({ (元素)
...
})
据我所知,获取特定元素,需要将其转换回数组,例如
let draggingFanArray = Array(draggingFan!)
这是我用来玩各种场景的游乐场代码:
进口Cocoa
var a: Array<Int>?
var b: ArraySlice<Int>?
a = [1, 2, 3, 4, 5, 6, 7]
b = a![3...5]
let count = b!.count
b!.forEach({ (element) in
print("\(element)")
})
let c = Array(b!)
print(c[2])
编辑 ArraySlice 扩展:
extension ArraySlice {
func elementAtIndex(index: Int)->AnyObject?{
return Array(self)[index] as? AnyObject
}
}
ArraySlice
的索引仍然与原始数组的索引匹配。在您的情况下,您正在访问不在您的切片中的索引 1
。如果您将索引偏移 draggingFan.startIndex
它将起作用:
if let draggingFan = draggingFan {
for i in 1 ..< draggingFan.count {
let card = draggingFan[draggingFan.startIndex + i]
...
}
}
或者:
if let draggingFan = draggingFan {
for i in draggingFan.startIndex + 1 ..< draggingFan.endIndex {
let card = draggingFan[i]
...
}
}
这将访问从切片中第二个元素到切片中最后一个元素的值:
let original = [1,2,3,4,5,6] // Int array to demonstrate
var draggingFan : ArraySlice<Int>?
draggingFan = original[1...4] // create the slice
if let draggingFan = draggingFan {
// so there's no errors just slice the slice and iterate over it
for i in draggingFan[(draggingFan.startIndex+1)..<draggingFan.endIndex] {
print(i, terminator: ", ")
}
}
输出:
3, 4, 5,
如果我有一个数组:
var arr = [1, 2, 3, 4, 5, 6, 7] // [1, 2, 3, 4, 5, 6, 7]
然后我取出数组的一部分:
let slice = arr[3..<arr.count] // [4, 5, 6, 7]
此切片的 startIndex
为 3,这意味着索引从 3 开始到 6 结束。
现在,如果我想要一个包含除第一个元素之外的所有元素的切片,我可以使用 dropFirst()
方法:
let sliceMinusFirst = slice.dropFirst() // [5, 6, 7]
此时,sliceMinusFirst
的 startIndex
为 4,这意味着我的索引范围为 4 到 6。
现在,如果我想遍历这些以对项目执行某些操作,我可以执行以下操作:
for item in sliceMinusFirst {
print(item)
}
或者,我可以用 forEach
:
sliceMinusFirst.forEach { item in
print(item)
}
通过使用这些形式的迭代,startIndex
不为零这一事实甚至都不重要,因为我不直接使用索引。没关系,在吃了一片之后,我想放下第一个项目。我能够轻松地做到这一点。我什至可以在我想进行迭代时做到这一点:
slice.dropFirst().forEach { item in
print(item)
}
这里我从原始切片中删除了第一项,没有创建任何中间变量。
请记住,如果您需要实际使用索引,您可能做错了什么。如果您真的需要索引,请确保您了解发生了什么。
此外,如果您想在创建切片后恢复到从零开始的索引,您可以从切片创建一个数组:
let sliceArray = Array(slice) // [4, 5, 6, 7]
sliceArray.startIndex // 0
下面我试图获取 ArraySlice
draggignFan
的第 i 个元素。代码构建良好(没有警告)但程序在运行时死于我尝试像普通数组一样索引切片的行:
var draggingFan : ArraySlice<Card>?
...
if let draggingFan = draggingFan {
for i in 1 ..< draggingFan.count {
let card = draggingFan[i] // EXECUTION ERROR HERE
...
}
}
根据 the docs 有一个 first
和 last
方法(我在别处使用没有问题)。那么如何在 Swift 中索引一个 ArraySlice
呢? (注意:我故意跳过切片中的第 0 个索引——其他地方需要)。
您遇到此问题的原因是切片保留了您从中获取的序列的原始索引号。因此,元素 1 不在此切片中。
例如,考虑以下代码:
let arr = [1,2,3,4,5,6,7,8,9]
let slice = arr[2...5]
现在 slice[1]
是什么?它不是 4
,即使那是切片中的第二个东西。它是 2
,因为切片仍然指向原始数组。换句话说,slice[1]
超出了切片的范围!这就是您收到运行时错误的原因。
怎么办?那么,切片的实际索引是它的 indices
。 那个 是你想要循环的。但是......你不想要切片指向的第一个元素。所以你需要推进你要迭代的范围的 startIndex
。因此:
if let draggingFan = draggingFan {
var ixs = draggingFan.indices
ixs.startIndex = ixs.startIndex.advancedBy(1)
for i in ixs {
// ... now your code will work ...
}
}
但是,在我看来,根本没有必要为切片建立索引,您也不应该这样做。您应该循环遍历 切片本身 ,而不是遍历其索引。你有这个:
for i in 1 ..< draggingFan.count
但这很像在说
for aCard in draggingFan
...除了您想删除切片的第一个元素。那就放下吧!这么说:
for aCard in draggingFan.dropFirst()
要了解这是否有效,请在 playground 中尝试:
let arr = [1,2,3,4,5,6,7,8,9]
let slice = arr[2...5]
for anInt in slice.dropFirst() {
print(anInt) // 4, 5, 6
}
如您所见,我们正在循环遍历所需的元素,根本没有参考索引号。
迭代切片中的元素: draggingFan?.forEach({ (元素) ... })
据我所知,获取特定元素,需要将其转换回数组,例如
let draggingFanArray = Array(draggingFan!)
这是我用来玩各种场景的游乐场代码:
进口Cocoa
var a: Array<Int>?
var b: ArraySlice<Int>?
a = [1, 2, 3, 4, 5, 6, 7]
b = a![3...5]
let count = b!.count
b!.forEach({ (element) in
print("\(element)")
})
let c = Array(b!)
print(c[2])
编辑 ArraySlice 扩展:
extension ArraySlice {
func elementAtIndex(index: Int)->AnyObject?{
return Array(self)[index] as? AnyObject
}
}
ArraySlice
的索引仍然与原始数组的索引匹配。在您的情况下,您正在访问不在您的切片中的索引 1
。如果您将索引偏移 draggingFan.startIndex
它将起作用:
if let draggingFan = draggingFan {
for i in 1 ..< draggingFan.count {
let card = draggingFan[draggingFan.startIndex + i]
...
}
}
或者:
if let draggingFan = draggingFan {
for i in draggingFan.startIndex + 1 ..< draggingFan.endIndex {
let card = draggingFan[i]
...
}
}
这将访问从切片中第二个元素到切片中最后一个元素的值:
let original = [1,2,3,4,5,6] // Int array to demonstrate
var draggingFan : ArraySlice<Int>?
draggingFan = original[1...4] // create the slice
if let draggingFan = draggingFan {
// so there's no errors just slice the slice and iterate over it
for i in draggingFan[(draggingFan.startIndex+1)..<draggingFan.endIndex] {
print(i, terminator: ", ")
}
}
输出:
3, 4, 5,
如果我有一个数组:
var arr = [1, 2, 3, 4, 5, 6, 7] // [1, 2, 3, 4, 5, 6, 7]
然后我取出数组的一部分:
let slice = arr[3..<arr.count] // [4, 5, 6, 7]
此切片的 startIndex
为 3,这意味着索引从 3 开始到 6 结束。
现在,如果我想要一个包含除第一个元素之外的所有元素的切片,我可以使用 dropFirst()
方法:
let sliceMinusFirst = slice.dropFirst() // [5, 6, 7]
此时,sliceMinusFirst
的 startIndex
为 4,这意味着我的索引范围为 4 到 6。
现在,如果我想遍历这些以对项目执行某些操作,我可以执行以下操作:
for item in sliceMinusFirst {
print(item)
}
或者,我可以用 forEach
:
sliceMinusFirst.forEach { item in
print(item)
}
通过使用这些形式的迭代,startIndex
不为零这一事实甚至都不重要,因为我不直接使用索引。没关系,在吃了一片之后,我想放下第一个项目。我能够轻松地做到这一点。我什至可以在我想进行迭代时做到这一点:
slice.dropFirst().forEach { item in
print(item)
}
这里我从原始切片中删除了第一项,没有创建任何中间变量。
请记住,如果您需要实际使用索引,您可能做错了什么。如果您真的需要索引,请确保您了解发生了什么。
此外,如果您想在创建切片后恢复到从零开始的索引,您可以从切片创建一个数组:
let sliceArray = Array(slice) // [4, 5, 6, 7]
sliceArray.startIndex // 0