Swift: Loop Over Array Elements and Access Previous and Next Elements

Get next or previous item to an object in a Swift collection or array

A good way to approach this is with an extension on the Swift Array, or in this case a more generalised solution for all BidirectionalCollection objects, including arrays.

The following provides methods for getting the next or previous object after your specified object from an array, with an optional parameter if you want the function to loop at the ends of the array.

These functions return nil if the original object is not present in the Array, and also if you ask for the previous item to the first object or the item that follows the last object, for the non-looping functions.

//
// Array+Iterator.swift
//

extension BidirectionalCollection where Iterator.Element: Equatable {
typealias Element = Self.Iterator.Element

func after(_ item: Element, loop: Bool = false) -> Element? {
if let itemIndex = self.index(of: item) {
let lastItem: Bool = (index(after:itemIndex) == endIndex)
if loop && lastItem {
return self.first
} else if lastItem {
return nil
} else {
return self[index(after:itemIndex)]
}
}
return nil
}

func before(_ item: Element, loop: Bool = false) -> Element? {
if let itemIndex = self.index(of: item) {
let firstItem: Bool = (itemIndex == startIndex)
if loop && firstItem {
return self.last
} else if firstItem {
return nil
} else {
return self[index(before:itemIndex)]
}
}
return nil
}
}

Usage:
If you have an array of your children, and want to know the child that comes after Jane, you would use the following:

let nextChild = children.after(jane)

If you simply want to know whose turn it is to do the dishes, and Sammy did them last night, you'd instead use:

let dishwasherTonight = children.after(sammy, loop: true)

That way, if Sammy is the youngest child, his oldest sibling will be assigned to wash the dishes tonight as we loop back to the start of the array.


Postscript: note re the comparison to endIndex in the code the definition of that property:

You can access an element of a collection through its subscript by
using any valid index except the collection’s endIndex property. This
property is a “past the end” index that does not correspond with any
element of the collection.

Iterate through Swift array and change values

I found a simple way and would like to share it.

The key is the definition of myArray. It would success if it's in this way:

 let myArray : [NSMutableDictionary] = [["firstDict":1, "otherKey":1], ["secondDict":2, "otherKey":1], ["lastDict":2, "otherKey":1]]

myArray.enumerated().forEach{$0.element["index"] = $0.offset}

print(myArray)






[{
firstDict = 1;
index = 0;
otherKey = 1;
}, {
index = 1;
otherKey = 1;
secondDict = 2;
}, {
index = 2;
lastDict = 2;
otherKey = 1;
}]

Move to next element in array every time it calls the function Swift 3

Get index of current Image from array and increment 1. If array indices doesn't contains next image index use 0th image. If imageview doesn't have any images show 0th image. Try this.

func nextImage()
{
let currentIndex = arrayPhoto.index(of: imageView.image ?? UIImage()) ?? -1
var nextIndex = currentIndex+1
nextIndex = arrayPhoto.indices.contains(nextIndex) ? nextIndex : 0
imageView.image = arrayPhoto[nextIndex]
}

Is there a way to show the next element in an array?

Make a counter and use modulo:

var array = ["one", "two", "three"]
var counter = 0

@IBAction func Button(_ sender: Any) {
print(array[counter % array.count])
counter += 1
}

Checking all elements in an array in Swift against each other


Not sure about the circle's array but to check each element of the circle's array against each other you can use a nested loop. The below code might help you.

for i in 0..<circles.count{
circles[i].center = getRandomPoint()
for j in 0..<circles.count{
if(i != j){
let comparingCentre = circles[j].center
let dist = distance(comparingCentre, circles[i].center)
if dist <= 50 {

var newCenter = circles[i].center
var centersVector = CGVector(dx: newCenter.x - comparingCentre.x, dy: newCenter.y - comparingCentre.y)

centersVector.dx *= 51 / dist
centersVector.dy *= 51 / dist
newCenter.x = comparingCentre.x + centersVector.dx
newCenter.y = comparingCentre.y + centersVector.dy
circles[i].center = newCenter
}
}
}
}

Spilt Array into pairs

How about this:

let a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9]

let pairs = Array(zip(a, a.dropFirst())).map {[$0.0, $0.1] }

print(pairs)

That outputs

[[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]

Edit:

If you want arbitrary chunk-size, you could write the extension like this:

extension Array {
func chunks(_ chunkSize: Int, includePartialChunk: Bool = true) -> [[Element]] {
var indexes = Array<Int>(stride(from: 0, to: count, by: chunkSize - 1))
if includePartialChunk,
let last = indexes.last,
last < count - 1 {
indexes.append(count-1)
}
return zip(indexes, indexes.dropFirst()).map {Array(self[$0.0...$0.1])}
}
}

Use the parameter includePartialChunk to tell the function if you want to include a "partial chunk" at the end when the array size is not an even multiple of the chunk-size. If true (The default) it returns a last chunk that is smaller than chunkSize but goes to the end of the array. If false, it only returns full-sized chunks, but will skip array elements at the end that don't fit into a full-sized chunk.

(I'll have to study Leo's UnfoldSequence version and see if I can adapt my code to that.)

Iterate over collection two at a time in Swift

You can use a progression loop called stride(to:, by:) to iterate over your elements every n elements:

let array = Array(1...5)

let pairs = stride(from: 0, to: array.endIndex, by: 2).map {
(array[$0], $0 < array.index(before: array.endIndex) ? array[$0.advanced(by: 1)] : nil)
} // [(.0 1, {some 2}), (.0 3, {some 4}), (.0 5, nil)]

print(pairs) // "[(1, Optional(2)), (3, Optional(4)), (5, nil)]\n"

To iterate your collection subsequences instead of tuples:

extension Collection {
func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence<SubSequence,Index> {
sequence(state: startIndex) { start in
guard start < self.endIndex else { return nil }
let end = self.index(start, offsetBy: maxLength, limitedBy: self.endIndex) ?? self.endIndex
defer { start = end }
return self[start..<end]
}
}
}


let array = Array(1...5)
for subsequence in array.unfoldSubSequences(limitedTo: 2) {
print(subsequence) // [1, 2] [3, 4] [5]
}

This would work on any kind of collection:

let string = "12345"
for substring in string.unfoldSubSequences(limitedTo: 2) {
print(substring) // "12" "34" "5"
}

How to iterate a loop with index and element in Swift

Yes. As of Swift 3.0, if you need the index for each element along with its value, you can use the enumerated() method to iterate over the array. It returns a sequence of pairs composed of the index and the value for each item in the array. For example:

for (index, element) in list.enumerated() {
print("Item \(index): \(element)")
}

Before Swift 3.0 and after Swift 2.0, the function was called enumerate():

for (index, element) in list.enumerate() {
print("Item \(index): \(element)")
}

Prior to Swift 2.0, enumerate was a global function.

for (index, element) in enumerate(list) {
println("Item \(index): \(element)")
}

How do I loop back to the first item in an Array?

A common solution is to use % (the remainder operator) to wrap firstQuote back to 0 when it is equal to quotes.count:

firstQuote = (firstQuote + 1) % quotes.count


Related Topics



Leave a reply



Submit