New Array from Index Range Swift


In Swift, you can create an array using the ArraySlice type. The following examples will show how to use the ArraySlice type. You can create an extension as well to define the subscript method.

Example 1

In the following example, we create an array of numbers with values from 0 to 9 and then create a range of indices from startIndex to endIndex (exclusive). Using this range we can generate an ArraySlice of the original array. In the end, we will convert the ArraySlice to an array using the Array initializer and print the result.

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)")

Output

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

Note that the startIndex is inclusive, while the endIndex is exclusive. This means that the new array will contain the elements from the original array starting at startIndex but it will not include endIndex.

Example 2

Suppose you have an array of Student objects, where each student has a name and an age. Assume that you want to get a new array that contains students between the ages of 25 and 35. To get these students, you can use the range of indices.

Algorithm

Step 1 − In this example, we use the firstIndex(where:) method to find the index of the first student whose age is greater than or equal to 25. We use the nil-coalescing operator ?? to provide a default value of 0 if the firstIndex method returns nil (i.e., if there is no student with an age of 25 or greater).

Step 2 − We do the same thing to find the index of the first student whose age is greater than 35. Here we use the endIndex property of the student array in case there is no such student above 35 years of age.

Step 3 − Finally, we create a new array by slicing the array of the original students using the start and end indices we computed and then converting the resulting ArraySlice to an array using the Array initializer.

Step 4 − The resulting filteredStudents array will contain only students with ages between 25 and 35, in the order, they appear in the original student's array.

Step 5 − Remember that the range of indices is half-open means the student with the age 25 will be included in the new array, but the student with the age 35 will not (assuming there is such a student in the original array).

Here is the Code

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)
}

Output

Original Student Names: - 
Alice
Bob
Charlie
Dave
Eve
Frainke

Filtered Student Names: - 
Alice
Bob
Charlie

Recommended Approach

There is another efficient and safe approach to creating a new array using an index range. In this approach, you can create an extension like the one below −

Example

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])

Output

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]

Conclusion

In Swift, it's normal practice to create a new array from a set of indices, and depending on your requirements, there are various approaches you can take.

To construct a new array from a partially open range of indices, use the Array initializer with a slice of the original array. Although this is a clear and concise method, you must manually calculate the start and end indices.

To offer more practical ways to create slices of an array, you may alternatively use an extension on Array. With this more adaptable approach, you can make slices using inclusive, exclusive, or partially open ranges of indices.

Updated on: 11-Apr-2023

573 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements