Swift 中根据索引范围创建新数组


在 Swift 中,你可以使用 ArraySlice 类型创建一个数组。以下示例将展示如何使用 ArraySlice 类型。你也可以创建一个扩展来定义下标方法。

示例 1

在下面的示例中,我们创建了一个包含 0 到 9 值的数字数组,然后创建了一个从 startIndex 到 endIndex(不包含 endIndex)的索引范围。使用此范围,我们可以生成原始数组的 ArraySlice。最后,我们将使用 Array 初始化器将 ArraySlice 转换为数组并打印结果。

import Foundation
let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let startIndex = 3 // inclusive
let endIndex = 8 // exclusive
let slice = numbers[startIndex..<endIndex] // return an ArraySlice<Int>
let newArray = Array(slice) // converts ArraySlice<Int> to [Int]
print("Original array: \(numbers)")
print("New array: \(newArray)")

输出

Original array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
New array: [3, 4, 5, 6, 7]

请注意,startIndex 是包含的,而 endIndex 是不包含的。这意味着新数组将包含从 startIndex 开始的原始数组中的元素,但不包括 endIndex。

示例 2

假设你有一个 Student 对象数组,其中每个学生都有姓名和年龄。假设你想要获取一个包含 25 到 35 岁学生的新数组。要获取这些学生,可以使用索引范围。

算法

步骤 1 − 在此示例中,我们使用 firstIndex(where:) 方法查找年龄大于或等于 25 的第一个学生的索引。我们使用 nil 合并运算符 ?? 来提供一个默认值 0,如果 firstIndex 方法返回 nil(即,如果没有年龄为 25 或更大的学生)。

步骤 2 − 我们做同样的事情来查找年龄大于 35 的第一个学生的索引。如果不存在年龄超过 35 岁的学生,我们在这里使用 student 数组的 endIndex 属性。

步骤 3 − 最后,我们通过使用我们计算的起始和结束索引切片原始学生的数组,然后使用 Array 初始化器将生成的 ArraySlice 转换为数组来创建一个新数组。

步骤 4 − 生成的 filteredStudents 数组将只包含年龄在 25 到 35 岁之间的学生,顺序与他们在原始学生数组中出现的顺序相同。

步骤 5 − 请记住,索引范围是半开区间,这意味着年龄为 25 的学生将包含在新数组中,但年龄为 35 的学生将不会包含(假设原始数组中存在这样的学生)。

代码如下

import Foundation
struct Student {
   let name: String
   let age: Int
}
let students = [
   Student(name: "Alice", age: 30),
   Student(name: "Bob", age: 25),
   Student(name: "Charlie", age: 35),
   Student(name: "Dave", age: 40),
   Student(name: "Eve", age: 20),
   Student(name: "Frainke", age: 33)
]
let startingIndex = students.firstIndex { $0.age >= 25 } ?? 0
let endingIndex = students.firstIndex { $0.age > 35 } ?? students.endIndex
let filteredStudents = Array(students[startingIndex..<endingIndex])
print("Original Student Names: - ")
students.forEach { student in
   print(student.name)
}
print("Filtered Student Names: - ")
filteredStudents.forEach { student in
   print(student.name)
}

输出

Original Student Names: - 
Alice
Bob
Charlie
Dave
Eve
Frainke

Filtered Student Names: - 
Alice
Bob
Charlie

推荐方法

还有一种高效且安全的方法可以根据索引范围创建新数组。在这种方法中,你可以创建如下所示的扩展 −

示例

import Foundation
extension Array {
    
   public subscript(safe bounds: Range<Int>) -> ArraySlice<Element> {
      if bounds.lowerBound > count { return [] }
      let lower = Swift.max(0, bounds.lowerBound)
      let upper = Swift.max(0, Swift.min(count, bounds.upperBound))
      return self[lower..<upper]
   }
    
   public subscript(safe lower: Int?, _ upper: Int?) -> ArraySlice<Element> {
      let lower = lower ?? 0
      let upper = upper ?? count
      if lower > upper { return [] }
      return self[safe: lower..<upper]
   }
}
let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print("Original array: \(numbers)")
print(numbers[safe: 0..<1])
print(numbers[safe: 5..<100])
print(numbers[safe: -5..<50])
print(numbers[safe: 5, 10])

输出

Original array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0]
[5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[5, 6, 7, 8, 9]

结论

在 Swift 中,根据一组索引创建一个新数组是很常见的做法,根据你的需求,你可以采取各种方法。

要根据部分开区间索引构造一个新数组,请使用带有原始数组切片的 Array 初始化器。虽然这是一种清晰简洁的方法,但是你必须手动计算起始和结束索引。

为了提供更实用的创建数组切片的方法,你可以选择对 Array 使用扩展。使用这种更灵活的方法,你可以使用包含式、排除式或部分开区间索引创建切片。

更新于:2023年4月11日

874 次浏览

启动你的职业生涯

完成课程获得认证

开始学习
广告