This question already has answers here:
Swift: What's the best way to pair up elements of an Array
(5 answers)
Closed 4 years ago.
How can I compare the two consecutive numbers in an array and find its count.
let numberArray = [1,2,4,6,7,10,12,13]
// I want to compare two consecutive numbers like [1,2], [4,6], [7,10], [12,13]
For example:
First, I want to calculate difference of the first two numbers[1,2(difference=1)]in the array, then the next two numbers[4,6(difference=2)], then[7,10(difference=3)] and [12,13(difference=1)] at last.
Lastly, I want to count a number of difference that has 1. In this case the count is 2.
What method should I use for this one?
Thanks in advance.
From this answer by Martin R, you can check how to create pairs as below,
let input = [1,2,4,6,7,10,12,13]
let output = stride(from: 0, to: input.count - 1, by: 2).map{(input[$0], input[$0 + 1])}
Now you can create differences array and find the one's count as below,
let differences = output.map({ $0.1 - $0.0 })
let onesCount = differences.filter({ $0 == 1}).count
print(differences)
print(onesCount)
Output
[1, 2, 3, 1]
2
I'm sure there are nicer ways to do this (but it's Monday morning).
One easy solution is to loop through the array using a stride, allowing you to take steps off two.
You then append each difference to a new difference array.
And finally use a filter on this resulting array to determine how often that difference occurs.
let difference = 1
let array = [1,2,4,6,7,10,12,13]
var differenceArray = [Int]()
for index in stride(from: 1, to: array.count, by: 2) {
let difference = array[index]-array[index-1]
differenceArray.append(difference)
}
print(differenceArray.filter{ $0 == difference }.count)
Good answer by #Philip. Here is an updated solution also handled other cases.
let numbers = [1, 2, 5, 4, 10, 6, 7, 8, 11, 10, 23]
var allDifference: [Int] = []
for index in stride(from: 0, to: numbers.count, by: 2) {
let firstValue = numbers[index]
let secondValue = ((index == numbers.count - 1 && numbers.count % 2 != 0) ? 0 : numbers[index + 1])
allDifference.append(abs(firstValue - secondValue))
}
let oneDifferenceCount = allDifference.filter { $0 == 1 }.count
print("Result: ", oneDifferenceCount)
You can achieve this with a 2 lines of code using zip compactMap and reduce:
First we create a tuple of consecutive elements, we use zip in order to use the index of the element and compactMap to filter nil elements then we reduce the new array to count only the tuples with a difference of 1
//Create tuples of consecutive values
let tuples = zip(numberArray.indices, numberArray).compactMap{$0 % 2 == 0 ? nil : (numberArray[$0-1],$1) }
// reduce to count only the tuples with difference of 1
let diffOneCount = tuples.reduce(0,{$1.0+1 == $1.1 ? $0+1 : $0})
Related
var number: [Int] = [1,2,3,4]
var newArray: [Int] = []
for i in 0...number.count-1{
newArray = number[i] * number[i+1]
}
print(newArray)
I want output like this: [1 * 2, 2 * 3, 3 * 4].
I just don't get it where is the problem...
var number: [Int] = [1,2,3,4]
let things = zip(number, number.dropFirst()).map(*)
Whenever you need to turn something like [1, 2, 3, 4] into pairs (1, 2), (2, 3) etc, then the AdjacentPairs method is useful - in Swift Algorithms package - https://github.com/apple/swift-algorithms/blob/main/Sources/Algorithms/AdjacentPairs.swift
Or you can zip a collection with its dropFirst for the same result.
And whenever you need to turn an [A]s into an [B]s then map with a function that turns As into Bs. So in this example you want to turn an array of tuples of Int, like [(1,2), (2,3), (3,4)] into array of Int, like [2, 6, 12] by multiplying the 2 Ints together, so map with *
The benefit of writing it this way is you would avoid the issues with your array mutation, getting index values wrong, running off the ends of arrays etc, and it's often easier to read and think about if you express it without the indices and assignments.
The problem that the compiler flags you is that you assign a single Int value to an array of Int. The following line will resolve that immediate issue:
newArray.append(number[i] * number[i+1])
This should pass compilation but then create a runtime error at execution. The reason is that when you try to fetch number[i+1] when i == number.count-1, you actually fetch number[number.count]. This entry does not exist with 0-based indices. To get 3 sums out of 4 array entries, your loop should iterate 3 times:
for i in 0 ..< number.count-1 {
Or, if you prefer closed ranges:
for i in 0 ... number.count-2 {
A more Swifty way would be to use map, as #Dris suggested. The return type for map is implicitly given by the result of the multiplication, so you can write:
let newArray = number.indices.dropLast().map { i in
number[i] * number[i+1]
}
You can use map()
let numbers = [1,2,3,4]
let newArray = numbers.enumerated().map { $1 * numbers[($0 + 1) % numbers.count] }
May be you should not loop to count-1 but stop before and add result to array :
for i in 0..<number.count-1 {
newArray.append(number[i] * number[i+1])
}
So, something is bugging me with the syntax in Swift for performing operations on Arrays of Ints.
What I wanna do is this : I have an array of Ints which is outputted from a function, its size (count) varies between say 2 and 6 for now, depending on buttons I press in my app.
For each array that is outputted and that contain n ints, I want to create n arrays on which to perform an other action later on.
These "sub" arrays are supposed to be calculated this way :
newArray1's values should be array's values - the value of the first index of newArray1
newArray2's values should be array's values - the value of the second index of newArray2
etc... (I'll automate the number of newArrays according to the array.count)
An other condition applying for those new arrays is that if at a given index the value is negative, I add 12 (so it'll occur for newArray2 at index 1, for newArray3 at indexes 1 & 2, etc... as long as those newArrays are created).
Here's how I wanted to perform that (I created this with dummy arbitrary array in the playground for the sake of testing before inserting the correct stuff in my app code) :
var array : [Int] = [2,4,6,8,9]
var newArray2 = [Int]()
var increment2 = Int()
increment2 = array[1]
newArray2 = array.map {$0 - increment2}
for i in 0..<newArray2.count {
if array[i] < 0 {
newArray2[i] = array[i] + 12
} else {
newArray2[i] = array[i]
}
}
print(array)
print(newArray2)
So of course it doesn't work because I can't seem to figure how to correctly perform operations on Arrays...
Intuitively it seems in my first if statement I'm comparing not the element at index i but i itself, not sure how to reformat that though...
Any help is most welcome, thanks in advance ! :)
[EDIT: I just edited the names of newArray1 to newArray2, same for increments, so that I have negative values and it matches the index value of 1 which is the second element of my main array]
You seem to mean this:
let arr = [2,4,6,8,9]
var results = [[Int]]()
for i in arr.indices {
results.append(arr.map {
var diff = $0-arr[i]
if diff < 0 { diff += 12 }
return diff
})
}
// results is now:
// [[0, 2, 4, 6, 7],
// [10, 0, 2, 4, 5],
// [8, 10, 0, 2, 3],
// [6, 8, 10, 0, 1],
// [5, 7, 9, 11, 0]]
This question already has answers here:
How to multiply two arrays element-wise
(5 answers)
Closed 3 years ago.
I am trying to compute the difference between the values in two arrays in Swift. I want to subtract values at each index between two arrays.
I tried doing the following:
var array1 : [Double] = [1, 2, 3, 4, 5]
var array2 : [Double] = [2, 3, 4, 5, 6]
var result = array2 - array1
Expected answer:
result = [1, 1, 1, 1, 1]
I get the following error message:
Binary operator '-' cannot be applied to two '[Double]' operands
The following worked:
var array1 : [Double] = [1, 2, 3, 4, 5]
var array2 : [Double] = [2, 3, 4, 5, 6]
let velocity = (0..<5).map { array2[$0] - array1[$0] }
print(velocity)
I wanted to understand if there is an efficient way to accomplish this.
Your attempt works quite well. In general, you would need to check which array has the fewer elements (just in case):
(0..<(min(array1.count, array2.count))).map { array2[$0] - array1[$0] }
Or, as Connor mentioned in their answer, use zip, which handles this comparison of array lengths for you.
zip(lhs, rhs).map { $0.0 - $0.1 }
You can go one step further and overload the - operator to achieve the syntax you wanted (array1 - array2):
func -<T: Numeric>(lhs: [T], rhs: [T]) -> [T] {
return zip(lhs, rhs).map(-)
}
// usage:
print([1,2,3] - [0, 1, 2])
But do note that, to other people, it might be quite unclear what an array “minus” another array means.
You can zip the 2 arrays together to get pairs of elements, and then map over them:
let result = zip(array1, array2).map { $0 - $1 }
Note that, with this method, if one array has more elements than the other, those extra elements will be ignored.
Let's say array A holds this:
[0, 1, 8, 3, 10, 6, 2]
And array B holds this:
[1, 2]
How can I generate a random index in array A which value does not appear in array B? Possible indexes in above example are:
0, 2, 3, 4, 5
But how to do this in Swift?
When you want to work with Array elements and their indices, enumerated() can be a good tool:
var a = [0, 1, 8, 3, 10, 6, 2]
var b = [1, 2]
var possibleIndices = a.enumerated()
.filter{!b.contains($0.element)}
.map{$0.offset}
print(possibleIndices)
//->[0, 2, 3, 4, 5]
(When b can be large, better make it a Set.)
And then:
(When we can assume b never holds all contents of a.)
var randomIndexToPossibleIndices = Int(arc4random_uniform(UInt32(possibleIndices.count)))
var randomIndex = possibleIndices[randomIndexToPossibleIndices]
If the assumption above cannot be satisfied, possibleIndices can be empty. So you'd better make randomIndex Optional:
var randomIndex: Int? = nil
if !possibleIndices.isEmpty {
var randomIndexToPossibleIndices = Int(arc4random_uniform(UInt32(possibleIndices.count)))
randomIndex = possibleIndices[randomIndexToPossibleIndices]
}
Thanks for Martin R.
First, you'd have to generate a diff between the 2 arrays ( unless they're both extremely large, in which case randomly trying recursively might result in better performance ).
Then all you have to do is find a random index you'd like to use and access said element:
#if os(Linux)
let j = Int(random() % ((count-1)))
#else
let j = Int(Int(arc4random()) % ((count-1)))
#endif
Will give you a proper index
If you then use this index and the element to find original element in your array you'll have your result.
If in case your elements are integers, and thus collisions can occur the thing I'd do would be recursively finding it to solve your problem. Remember that this can result in slow performance.
Look into the functional programming part of collections in swift here:
Swift Guide to map filter reduce
For instance you could use filter in the following way ( and I don't know if this is the best way ):
collection.filter {
var found = false;
for element in bCollection {
if element == $0 {
found = true;
}
}
return !found; // Might be better to turn true/false thing around in the above code to slightly improve performance.
}
How about working with sets?
let a = [0, 1, 8, 3, 10, 6, 2]
let b = [1, 2]
var setA = Set(a)
var setB = Set(b)
setA.subtract(setB)
var index: Int? = nil
if let first = setA.first {
index = a.index(of: first)
}
// if index == nil no such index exists
I have a big array of objects and would like to split it into two arrays containing the objects in alternate order.
Example:
[0, 1, 2, 3, 4, 5, 6]
Becomes these two arrays (they should alternate)
[0, 2, 4, 6] and [1, 3, 5]
There are a ton of ways to split an array. But, what is the most efficient (least costly) if the array is huge.
There are various fancy ways to do it with filter but most would probably require two passes rather than one, so you may as well just use a for-loop.
Reserving space up-front could make a big difference in this case since if the source is large it’ll avoid unnecessary re-allocation as the new arrays grow, and the calculation of space needed is in constant time on arrays.
// could make this take a more generic random-access collection source
// if needed, or just make it an array extension instead
func splitAlternating<T>(source: [T]) -> ([T],[T]) {
var evens: [T] = [], odds: [T] = []
evens.reserveCapacity(source.count / 2 + 1)
odds.reserveCapacity(source.count / 2)
for idx in indices(source) {
if idx % 2 == 0 {
evens.append(source[idx])
}
else {
odds.append(source[idx])
}
}
return (evens,odds)
}
let a = [0,1,2,3,4,5,6]
splitAlternating(a) // ([0, 2, 4, 6], [1, 3, 5])
If performance is truly critical, you could use source.withUnsafeBufferPointer to access the source elements, to avoid the index bounds checking.
If the arrays are really huge, and you aren’t going to use the resulting data except to sample a small number of elements, you could consider using a lazy view instead (though the std lib lazy filter isn’t much use here as it returns sequence not a collection – you’d possibly need to write your own).
You can use the for in stride loop to fill two resulting arrays as follow:
extension Array {
var groupOfTwo:(firstArray:[T],secondArray:[T]) {
var firstArray:[T] = []
var secondArray:[T] = []
for index in stride(from: 0, to: count, by: 2) {
firstArray.append(self[index])
if index + 1 < count {
secondArray.append(self[index+1])
}
}
return (firstArray,secondArray)
}
}
[0, 1, 2, 3, 4, 5, 6].groupOfTwo.firstArray // [0, 2, 4, 6]
[0, 1, 2, 3, 4, 5, 6].groupOfTwo.secondArray // [1, 3, 5]
update: Xcode 7.1.1 • Swift 2.1
extension Array {
var groupOfTwo:(firstArray:[Element],secondArray:[Element]) {
var firstArray:[Element] = []
var secondArray:[Element] = []
for index in 0.stride(to: count, by: 2) {
firstArray.append(self[index])
if index + 1 < count {
secondArray.append(self[index+1])
}
}
return (firstArray,secondArray)
}
}
A more concise, functional approach would be to use reduce
let a = [0,1,2,3,4,5,6]
let (evens, odds) = a.enumerate().reduce(([Int](),[Int]())) { (cur, next) in
let even = next.index % 2 == 0
return (cur.0 + (even ? [next.element] : []),
cur.1 + (even ? [] : [next.element]))
}
evens // [0,2,4,6]
odds // [1,3,5]
Big/huge array always pose problems when being partially processed, like in this case, as creating two extra (even if half-sized) arrays can be both time and memory consuming. What if, for example, you just want to compute the mean and standard deviation of oddly and evenly positioned numbers, but this will require calling a dedicated function which requires a sequence as input?
Thus why not creating two sub-collections that instead of duplicating the array contents, they point to the original array, in a transparent manner to allow querying them for elements:
extension Collection where Index: Strideable{
func stride(from: Index, to: Index, by: Index.Stride) -> StridedToCollection<Self> {
return StridedToCollection(self, from: from, to: to, by: by)
}
}
struct StridedToCollection<C>: Collection where C: Collection, C.Index: Strideable {
private let _subscript : (C.Index) -> C.Element
private let step: C.Index.Stride
fileprivate init(_ collection: C, from: C.Index, to: C.Index, by: C.Index.Stride) {
startIndex = from
endIndex = Swift.max(to, startIndex)
step = by
_subscript = { collection[$0] }
}
let startIndex: C.Index
let endIndex: C.Index
func index(after i: C.Index) -> C.Index {
let next = i.advanced(by: step)
return next >= endIndex ? endIndex : next
}
subscript(_ index: C.Index) -> C.Element {
return _subscript(index)
}
}
The Collection extension and the associated struct would create a pseudo-array that you can use to access only the elements you are interested into.
Usage is simple:
let numbers: [Int] = [1, 2, 3, 4]
let stride1 = numbers.stride(from: 0, to: numbers.count, by: 2)
let stride2 = numbers.stride(from: 1, to: numbers.count, by: 2)
print(Array(stride1), Array(stride2))
With the above you can iterate the two strides without worrying you'll double the amount of memory. And if you actually need two sub-arrays, you just Array(stride)-ify them.
Use for loops. If the index value is even then send that to one array and if the index value is odd, then send that to odd array.
Here's, in my opinion, the easiest way
old_list = [0, 1, 2, 3, 4, 5, 6]
new_list1 =[]
new_list2 = []
while len(old_list)>0:
new_list1.append(old_list.pop(-1))
if len(old_list) != 0:
new_list2.append(old_list.pop(-1))
new_list1.reverse()
new_list2.reverse()
I just had to do this where I split an array into two in one place, and three into another. So I built this:
extension Array {
/// Splits the receiving array into multiple arrays
///
/// - Parameter subCollectionCount: The number of output arrays the receiver should be divided into
/// - Returns: An array containing `subCollectionCount` arrays. These arrays will be filled round robin style from the receiving array.
/// So if the receiver was `[0, 1, 2, 3, 4, 5, 6]` the output would be `[[0, 3, 6], [1, 4], [2, 5]]`. If the reviever is empty the output
/// Will still be `subCollectionCount` arrays, they just all will be empty. This way it's always safe to subscript into the output.
func split(subCollectionCount: Int) -> [[Element]] {
precondition(subCollectionCount > 1, "Can't split the array unless you ask for > 1")
var output: [[Element]] = []
(0..<subCollectionCount).forEach { (outputIndex) in
let indexesToKeep = stride(from: outputIndex, to: count, by: subCollectionCount)
let subCollection = enumerated().filter({ indexesToKeep.contains($0.offset)}).map({ $0.element })
output.append(subCollection)
}
precondition(output.count == subCollectionCount)
return output
}
}
It works on Swift 4.2 and 5.0 (as of 5.0 with Xcode 10.2 beta 2)