Loop Through An Array Backwards (Swift) [duplicate] - arrays

When I use the for loop in Playground, everything worked fine, until I changed the first parameter of for loop to be the highest value. (iterated in descending order)
Is this a bug? Did any one else have it?
for index in 510..509
{
var a = 10
}
The counter that displays the number of iterations that will be executions keeps ticking...

Xcode 6 beta 4 added two functions to iterate on ranges with a step other than one:
stride(from: to: by:), which is used with exclusive ranges and stride(from: through: by:), which is used with inclusive ranges.
To iterate on a range in reverse order, they can be used as below:
for index in stride(from: 5, to: 1, by: -1) {
print(index)
}
//prints 5, 4, 3, 2
for index in stride(from: 5, through: 1, by: -1) {
print(index)
}
//prints 5, 4, 3, 2, 1
Note that neither of those is a Range member function. They are global functions that return either a StrideTo or a StrideThrough struct, which are defined differently from the Range struct.
A previous version of this answer used the by() member function of the Range struct, which was removed in beta 4. If you want to see how that worked, check the edit history.

Apply the reverse function to the range to iterate backwards:
For Swift 1.2 and earlier:
// Print 10 through 1
for i in reverse(1...10) {
println(i)
}
It also works with half-open ranges:
// Print 9 through 1
for i in reverse(1..<10) {
println(i)
}
Note: reverse(1...10) creates an array of type [Int], so while this might be fine for small ranges, it would be wise to use lazy as shown below or consider the accepted stride answer if your range is large.
To avoid creating a large array, use lazy along with reverse(). The following test runs efficiently in a Playground showing it is not creating an array with one trillion Ints!
Test:
var count = 0
for i in lazy(1...1_000_000_000_000).reverse() {
if ++count > 5 {
break
}
println(i)
}
For Swift 2.0 in Xcode 7:
for i in (1...10).reverse() {
print(i)
}
Note that in Swift 2.0, (1...1_000_000_000_000).reverse() is of type ReverseRandomAccessCollection<(Range<Int>)>, so this works fine:
var count = 0
for i in (1...1_000_000_000_000).reverse() {
count += 1
if count > 5 {
break
}
print(i)
}
For Swift 3.0 reverse() has been renamed to reversed():
for i in (1...10).reversed() {
print(i) // prints 10 through 1
}

Updated for Swift 3
The answer below is a summary of the available options. Choose the one that best fits your needs.
reversed: numbers in a range
Forward
for index in 0..<5 {
print(index)
}
// 0
// 1
// 2
// 3
// 4
Backward
for index in (0..<5).reversed() {
print(index)
}
// 4
// 3
// 2
// 1
// 0
reversed: elements in SequenceType
let animals = ["horse", "cow", "camel", "sheep", "goat"]
Forward
for animal in animals {
print(animal)
}
// horse
// cow
// camel
// sheep
// goat
Backward
for animal in animals.reversed() {
print(animal)
}
// goat
// sheep
// camel
// cow
// horse
reversed: elements with an index
Sometimes an index is needed when iterating through a collection. For that you can use enumerate(), which returns a tuple. The first element of the tuple is the index and the second element is the object.
let animals = ["horse", "cow", "camel", "sheep", "goat"]
Forward
for (index, animal) in animals.enumerated() {
print("\(index), \(animal)")
}
// 0, horse
// 1, cow
// 2, camel
// 3, sheep
// 4, goat
Backward
for (index, animal) in animals.enumerated().reversed() {
print("\(index), \(animal)")
}
// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse
Note that as Ben Lachman noted in his answer, you probably want to do .enumerated().reversed() rather than .reversed().enumerated() (which would make the index numbers increase).
stride: numbers
Stride is way to iterate without using a range. There are two forms. The comments at the end of the code show what the range version would be (assuming the increment size is 1).
startIndex.stride(to: endIndex, by: incrementSize) // startIndex..<endIndex
startIndex.stride(through: endIndex, by: incrementSize) // startIndex...endIndex
Forward
for index in stride(from: 0, to: 5, by: 1) {
print(index)
}
// 0
// 1
// 2
// 3
// 4
Backward
Changing the increment size to -1 allows you to go backward.
for index in stride(from: 4, through: 0, by: -1) {
print(index)
}
// 4
// 3
// 2
// 1
// 0
Note the to and through difference.
stride: elements of SequenceType
Forward by increments of 2
let animals = ["horse", "cow", "camel", "sheep", "goat"]
I'm using 2 in this example just to show another possibility.
for index in stride(from: 0, to: 5, by: 2) {
print("\(index), \(animals[index])")
}
// 0, horse
// 2, camel
// 4, goat
Backward
for index in stride(from: 4, through: 0, by: -1) {
print("\(index), \(animals[index])")
}
// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse
Notes
#matt has an interesting solution where he defines his own reverse operator and calls it >>>. It doesn't take much code to define and is used like this:
for index in 5>>>0 {
print(index)
}
// 4
// 3
// 2
// 1
// 0
Check out On C-Style For Loops Removed from Swift 3

Swift 4 onwards
for i in stride(from: 5, to: 0, by: -1) {
print(i)
}
//prints 5, 4, 3, 2, 1
for i in stride(from: 5, through: 0, by: -1) {
print(i)
}
//prints 5, 4, 3, 2, 1, 0

With Swift 5, according to your needs, you may choose one of the four following Playground code examples in order to solve your problem.
#1. Using ClosedRange reversed() method
ClosedRange has a method called reversed(). reversed() method has the following declaration:
func reversed() -> ReversedCollection<ClosedRange<Bound>>
Returns a view presenting the elements of the collection in reverse order.
Usage:
let reversedCollection = (0 ... 5).reversed()
for index in reversedCollection {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
As an alternative, you can use Range reversed() method:
let reversedCollection = (0 ..< 6).reversed()
for index in reversedCollection {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
#2. Using sequence(first:next:) function
Swift Standard Library provides a function called sequence(first:next:). sequence(first:next:) has the following declaration:
func sequence<T>(first: T, next: #escaping (T) -> T?) -> UnfoldFirstSequence<T>
Returns a sequence formed from first and repeated lazy applications of next.
Usage:
let unfoldSequence = sequence(first: 5, next: {
$0 > 0 ? $0 - 1 : nil
})
for index in unfoldSequence {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
#3. Using stride(from:through:by:) function
Swift Standard Library provides a function called stride(from:through:by:). stride(from:through:by:) has the following declaration:
func stride<T>(from start: T, through end: T, by stride: T.Stride) -> StrideThrough<T> where T : Strideable
Returns a sequence from a starting value toward, and possibly including, an end value, stepping by the specified amount.
Usage:
let sequence = stride(from: 5, through: 0, by: -1)
for index in sequence {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
As an alternative, you can use stride(from:to:by:):
let sequence = stride(from: 5, to: -1, by: -1)
for index in sequence {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
#4. Using AnyIterator init(_:) initializer
AnyIterator has an initializer called init(_:). init(_:) has the following declaration:
init(_ body: #escaping () -> AnyIterator<Element>.Element?)
Creates an iterator that wraps the given closure in its next() method.
Usage:
var index = 5
guard index >= 0 else { fatalError("index must be positive or equal to zero") }
let iterator = AnyIterator({ () -> Int? in
defer { index = index - 1 }
return index >= 0 ? index : nil
})
for index in iterator {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/
If needed, you can refactor the previous code by creating an extension method for Int and wrapping your iterator in it:
extension Int {
func iterateDownTo(_ endIndex: Int) -> AnyIterator<Int> {
var index = self
guard index >= endIndex else { fatalError("self must be greater than or equal to endIndex") }
let iterator = AnyIterator { () -> Int? in
defer { index = index - 1 }
return index >= endIndex ? index : nil
}
return iterator
}
}
let iterator = 5.iterateDownTo(0)
for index in iterator {
print(index)
}
/*
Prints:
5
4
3
2
1
0
*/

For Swift 2.0 and above you should apply reverse on a range collection
for i in (0 ..< 10).reverse() {
// process
}
It has been renamed to .reversed() in Swift 3.0

In Swift 4 and latter
let count = 50//For example
for i in (1...count).reversed() {
print(i)
}

Swift 4.0
for i in stride(from: 5, to: 0, by: -1) {
print(i) // 5,4,3,2,1
}
If you want to include the to value:
for i in stride(from: 5, through: 0, by: -1) {
print(i) // 5,4,3,2,1,0
}

If one is wanting to iterate through an array (Array or more generally any SequenceType) in reverse. You have a few additional options.
First you can reverse() the array and loop through it as normal. However I prefer to use enumerate() much of the time since it outputs a tuple containing the object and it's index.
The one thing to note here is that it is important to call these in the right order:
for (index, element) in array.enumerate().reverse()
yields indexes in descending order (which is what I generally expect). whereas:
for (index, element) in array.reverse().enumerate() (which is a closer match to NSArray's reverseEnumerator)
walks the array backward but outputs ascending indexes.

as for Swift 2.2 , Xcode 7.3 (10,June,2016) :
for (index,number) in (0...10).enumerate() {
print("index \(index) , number \(number)")
}
for (index,number) in (0...10).reverse().enumerate() {
print("index \(index) , number \(number)")
}
Output :
index 0 , number 0
index 1 , number 1
index 2 , number 2
index 3 , number 3
index 4 , number 4
index 5 , number 5
index 6 , number 6
index 7 , number 7
index 8 , number 8
index 9 , number 9
index 10 , number 10
index 0 , number 10
index 1 , number 9
index 2 , number 8
index 3 , number 7
index 4 , number 6
index 5 , number 5
index 6 , number 4
index 7 , number 3
index 8 , number 2
index 9 , number 1
index 10 , number 0

You can consider using the C-Style while loop instead. This works just fine in Swift 3:
var i = 5
while i > 0 {
print(i)
i -= 1
}

var sum1 = 0
for i in 0...100{
sum1 += i
}
print (sum1)
for i in (10...100).reverse(){
sum1 /= i
}
print(sum1)

You can use reversed() method for easily reverse values.
var i:Int
for i in 1..10.reversed() {
print(i)
}
The reversed() method reverse the values.

Reversing an array can be done with just single step .reverse()
var arrOfnum = [1,2,3,4,5,6]
arrOfnum.reverse()

This will works decrement by one in reverse order.
let num1 = [1,2,3,4,5]
for item in nums1.enumerated().reversed() {
print(item.offset) // Print the index number: 4,3,2,1,0
print(item.element) // Print the value :5,4,3,2,1
}
Or you can use this index, value property
let num1 = [1,2,3,4,5]
for (index,item) in nums1.enumerated().reversed() {
print(index) // Print the index number: 4,3,2,1,0
print(item) // Print the value :5,4,3,2,1
}

For me, this is the best way.
var arrayOfNums = [1,4,5,68,9,10]
for i in 0..<arrayOfNums.count {
print(arrayOfNums[arrayOfNums.count - i - 1])
}

Related

How can i sort a medal table array in Kotlin?

I'm working for a school project and i need to sort a multidimensional array using Kotlin. The array contains arrays of medals. I need to sort it like a medal table, where depending on the medal weight and medals count.
The array is something like this:
[0] -> [0,0,0,0,0] (for each index there is an array of 5 medals, each medal has a weight from 0 to 4, 0 is the is the least important, 4 is the most.
Example of populated array:
[0] -> [0,17,0,0,2]
[1] -> [1,0,0,0,0]
[2] -> [0,12,39,21,0]
[3] -> [0,13,0,11,17]
I need something like this:
[1] -> [1,0,0,0,0]
[0] -> [0,17,0,0,2]
[3] -> [0,13,0,11,17]
[2] -> [0,12,39,21,0]
Thank you very much.
You can use sortedArrayWith that takes a Comparator
Multiple options.
val medals = arrayOf(
arrayOf(0,17,0,0,2),
arrayOf(1,0,0,0,0),
arrayOf(0,12,39,21,0),
arrayOf(0,13,0,11,17)
)
val sorted = medals.sortedArrayWith { a1, a2 ->
a1.zip(a2)
.find { it.first != it.second }
?.let { it.second - it.first } ?: 0
}
or
val sorted = medals.sortedArrayWith { a1, a2 ->
a1.zip(a2).forEach {
if(it.first != it.second) return#sortedArrayWith it.second-it.first
}
0
}
Idea is to find the first pair/index where the counts don't match, and return the maximum value.
The solution is generic that would work with any size of nested array
If I understand your question correctly, you want to sort by the first, then the second, then the third, etc. element, and that in descending order:
val list = arrayOf(
arrayOf(0, 17, 0, 0, 2),
arrayOf(1, 0, 0, 0, 0),
arrayOf(0, 12, 39, 21, 0),
arrayOf(0, 13, 0, 11, 17)
)
val result = list
.sortedArrayWith(
compareByDescending<Array<Int>> { it[0] }
.thenByDescending { it[1] }
.thenByDescending { it[2] }
.thenByDescending { it[3] }
.thenByDescending { it[4] }
)
result.forEach { println(it.toList()) }
Just another quick general one, not necessarily the most efficient!
// basically sorting in reverse order, so each pass allows a group
// to move to a 'better' position
val sorted = medalGroups.apply {
// assuming they all have the same number of indices
// you could check with require(all { it.size == first().size }) or something
for (i in first().indices.reversed()) {
sortByDescending { it[i] }
}
}
Or to work off lukas.j's answer (which is better) if you want to avoid repetition:
val sorted = medalGroups.sortedArrayWith(
// start with the basic index 0 comparator, and tack one on for every other index
(1 until list.size).fold(compareByDescending { it[0] }) { comparator, i ->
comparator.thenByDescending { it[i] }
}
)
You could use a for loop instead but folds are cool

Why am I getting a Fatal error when I try removing an element from array inside a loop?

I have an array, I want to do some filtering in it, however, it gives me a runtime error. Is there any alternative way of doing this? (without using closures)
var arr = [4,5,6,7]
for i in 0..<arr.count - 1 {
if arr[i] > 2 {
arr.remove(at: i)
}
}
print(arr)
Think about what your code does.
if arr[i] > 2 { //#2
arr.remove(at: i)
}
}
At #1, it looks at the current number of elements in the array and sets the end value of the loop to 3. So the loop will run from 0 to 3.
At #2, each element in the array is greater than 2, so it gets removed from the array.
At i == 0 the 4 is removed. Now there are 3 elements
At i == 1, the
5 is removed. Now there are 2 elements
At i == 2, it attempts to
fetch an element at index 2, and crashes with an index out of range
error.
You are mutating the array as you attempt to iterate through it. Don't do that.
As others have said, use filter instead:
arr = arr.filter { $0 <= 2 }
If you really want to use a for loop and remove elements via index, loop through the array backwards:
var arr = [4,5,6,7]
for index in stride(from: arr.count-1, to: -1, by: -1) {
let thisValue = arr[index]
print("arr[\(index)]=\(thisValue)")
if thisValue > 2 {
arr.remove(at: index)
print("->> removing \(thisValue) from arr at index \(index)")
}
}
print("\nAfter for loop, arr contains \(arr.count) items")
arr.forEach {
print($0)
}
That ouputs:
arr[3]=7
->> removing 7 from arr at index 3
arr[2]=6
->> removing 6 from arr at index 2
arr[1]=5
->> removing 5 from arr at index 1
arr[0]=4
->> removing 4 from arr at index 0
After for loop, arr contains 0 items
This is a great example of why mutation is best avoided.
If you're manipulating an array and iterating over it at the same time, the index values are going to be invalid, because what was at index 4, will now be at index 3 if you delete something at position 1.
You can do it without 'using closures':
var idxToRemove: [Int] = []
for (idx, i) in arr.enumerated() {
if i > 2 {
idxToRemove.append(idx)
}
}
for i in idxToRemove.reversed() {
arr.remove(at: i)
}
But what you want is: let arr = [4,5,6,7].filter { $0 <= 2 }
var arr = [4, 5, 6, 7]
arr = arr.filter { $0 <= 2 }
print(arr)

Swift Comparison in consecutive numbers inside array and its count [duplicate]

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

If statements to find duplicate values?

Ok lets say I have a list which generates values randomly and sometimes it generates the same value twice.
For example generated int value:
1, 1, 2, 3, 4
Then I have a method called duplicateTracker() and its job is to find duplicates within the list.
I have an idea that it should be done using if else statements. So if it detects duplicate numbers its then true, else false.
How do I do this?
This makes use of Foundation methods but given your use case, you might want to consider making us of an NSCountedSet to keep track of your generated numbers. E.g.
let numbersGenerator = AnyIterator { return 1 + arc4random_uniform(10) }
var numbersBag = NSCountedSet()
for num in (0...15).flatMap({ _ in numbersGenerator.next()}) {
print(num, terminator: " ")
numbersBag.add(num)
} /* 1 3 2 2 10 1 10 7 10 6 8 3 8 10 7 4 */
print()
numbersBag.forEach { print($0, numbersBag.count(for: $0)) }
/* 1 2
2 2
3 2
4 1
6 1
7 2
8 2
10 4 */
Since NSCountedSet conforms to Sequence, you can easily extract any "duplicate diagnostics" that you wish using e.g. filter:
print("Numbers with duplicates: ", numbersBag.filter { numbersBag.count(for: $0) > 1 })
// Numbers with duplicates: [1, 2, 3, 7, 8, 10]
Given this function:
func checkForDups(_ arr1:[Int], _ arr2:[Int]) -> Bool {
let arrChecked = Set(arr1).subtracting(Set(arr2))
if Set(arr1).count != arrChecked.count {
return true
}
return false
}
Here's code that works:
let arr1:[Int] = [1,1,2,3,4,5]
let arr2:[Int] = [1,10,20]
let arr3:[Int] = [10,20,30]
print(checkForDups(arr1, arr2)) // prints true
print(checkForDups(arr1, arr3)) // prints false

How to specify starting value of index in Groovy's eachWithIndex method?

When using Groovy's eachWithIndex method the index value starts at 0, I need it to start at 1. How can I do that?
The index will always start from 0
Your options are:
1) Add an offset to the index:
int offs = 1
list.eachWithIndex { it, idx ->
println "$it # pos ${idx + offs}"
}
2) Use something other than eachWithIndex (ie: transpose a list of integers starting at 1 with your original list, and then loop through this)
3) You can also use default parameters to hack this sort of thing in... If we pass eachWithIndex a closure with 3 parameters (the two that eachWithIndex is expecting and a third with a default value of index + 1):
[ 'a', 'b', 'c' ].eachWithIndex { item, index, indexPlusOne = index + 1 ->
println "Element $item has position $indexPlusOne"
}
We will give the output:
Element a has position 1
Element b has position 2
Element c has position 3
I wouldn't use eachWithIndex at all, a for loop with .indexed(1) will be more elegant/readable:
for (item in ['a','b','c','d','e'].indexed(1)) {
println("element $item.key = $item.value")
}
outputs:
element 1 = a
element 2 = b
element 3 = c
element 4 = d
element 5 = e
caveat -- indexed(n) is only available in Groovy 2.4.0 onwards
What about just using a Range?
def offset = 1
def arr = [1,2,3,4,5]
def len = arr.size() - 1
arr[offset..len].eachWithIndex{n,i -> println "${i+offset}:$n"}
You could use some metaprogramming hackery as well:
def eachWithMyIndex = { init, clos ->
delegate.eachWithIndex { it, idx -> clos(it, idx + init) }
}
List.metaClass.eachWithMyIndex = eachWithMyIndex
[1,2,3].eachWithMyIndex(10) {n, idx -> println("element $idx = $n") }
gives output:
element 10 = 1
element 11 = 2
element 12 = 3

Resources