Since you know the both sequences to be increasing, you need only make use of the first and last element of the array a. Using these, you can make use of the index(where:) method to find the corresponding indices in the b array, fulfilling the predicate >= (first of a) and <= (last of a). E.g.
if let aFirst = a.first, let aLast = a.last,
let startIndex = b.index(where: { $0 >= aFirst }),
case let endIndex = b.index(where: { $0 > aLast }) ?? a.endIndex {
let c = b[startIndex..<endIndex] // note: this is an ArraySlice<Double>
// wrap in Array(..) to construct a new array
print(c)
// [0.0, 0.0040000000000000001, 0.0080000000000000002, 0.012, 0.016, 0.02, 0.024]
}
Or, as proposed by @MartinR, we can make a guess that we will, on avarage, more quickly fulfil the predicate of the second index(where:) call if we start from the end of b when checking for the first element that fulfills the $0 <= aLast condition:
if let aFirst = a.first, let aLast = a.last,
let startIndex = b.index(where: { $0 >= aFirst }),
case let endIndex = b.reversed().index(where: { $0 <= aLast })!.base {
/* ^^^^^- as proposed by @MartinR */
let c = b[startIndex..<endIndex]
print(c)
// [0.0, 0.0040000000000000001, 0.0080000000000000002, 0.012, 0.016, 0.02, 0.024]
}
In the end this approach (as well as the filter approach in the currently available other answers) runs in O(n). A more performant approach would be using binary search, which runs in O(log n) asymptotically. As also mentioned by @MartinR, a good starting point could be the binary search Swift implementations from the Rosetta code:
as mentioned in this Q&A:
Answering the comment:
... I also have another issue that I forgot to mention. I have another
array y that has exactly the same number of elements as b. We can
regard these as X and Y values of a signal. I have to choose the
matching elements from y for the elements I choose in b.
The simplest solution would simply apply the calculated startIndex and endIndex to slice out a part of the y array (just like you sliced out a part of b to construct c).
let d = y[startIndex..<endIndex]
// assumes y.count == b.count, and that these are not slices
// with non-matching indices
However, I believe a better approach would be using zip. Simply zip y and b and use the result to construct an array of tuples, whereafter you can apply the predicate above to the b members of the zipped sequence:
let y = Array(1...b.count)
if let aFirst = a.first, let aLast = a.last,
let startIndex = bAndY.index(where: { $0.0 >= aFirst }),
case let endIndex = bAndY.index(where: { $0.0 > aLast }) ?? a.endIndex {
let cAndD = bAndY[startIndex..<endIndex]
print(cAndD)
/* [(0.0040000000000000001, 2),
(0.0080000000000000002, 3),
(0.012, 4),
(0.016, 5),
(0.02, 6),
(0.024, 7)] */
}
Naturally constructing the cAndD array will yield a minor overhead, but unless you're coding some really HPC application, you shouldn't need to worry about that.