Swift: move array elements and access previous and next elements

In Swift, I want to iterate over an array and compare each element with the previous and / or next. For each comparison, I either create a new element or nothing. Is there a “functional” way to do this?

An example would be that I have an array Intand you want to find all the "local minima".

I could do it sequentially like this

let a = [ 1,2,2,3,5,4,2,5,7,9,5,3,8,10 ]
var i = 1
var r: [Int] = []

while i < a.count - 1 {
    if a[i] < a[i+1] && a[i] < a[i-1] {
        r.append(i)
    }
    i += 1
}

print(r)
// [6, 11]

I wonder if there is a simpler or more direct way to do this.

+4
source share
5 answers

, dropFirst() zip() . , :

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

let diffs = zip(a.dropFirst(), a).map(-)
print(diffs)
// [1, 0, 1, 2, -1, -2, 3, 2, 2, -4, -2, 5, 2]

a, a.dropFirst() a.dropFirst(2) . enumerated() flatMap() ( compactMap() Swift 4.1). , :

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

let localMins = zip(a.enumerated().dropFirst(), zip(a, a.dropFirst(2))).flatMap {
    $0.element < $1.0 && $0.element < $1.1 ? $0.offset : nil
}
print(localMins) // [6, 11]
+2

while i for stride.

let a = [ 1,2,2,3,5,4,2,5,7,9,5,3,8,10 ]
var r: [Int] = []

for i in stride(from: 1, to: a.count - 1, by: 1) {
    if a[i] < a[i+1] && a[i] < a[i-1] {
        r.append(i)
    }
}

print(r)
// [6, 11]

, , :

let a = [ 1,2,2,3,5,4,2,5,7,9,5,3,8,10 ]
let r = a.enumerated().dropFirst().dropLast().filter { $0.1 < a[$0.0 + 1] && $0.1 < a[$0.0 - 1] }.map { $0.0 }
print(r)
// [6, 11]
+1

,

for i in a.indices.dropFirst().dropLast()
{
    if a[i] < a[a.index(after: i)],
            a[i] < a[a.index(before: i)] {
        r.append(i)
    }
}
print(r)
// [6, 11]

, - ,

let result = a.indices.dropLast().dropFirst().filter { i in
    return a[i] < a[a.index(after: i)] &&
            a[i] < a[a.index(before: i)]
}
print(r)
// [6, 11]

Or short

let result = a.indices.dropLast()
                      .dropFirst()
                      .filter { a[$0] < a[$0 + 1] &&
                                a[$0] < a[$0 - 1] }
 print(result)
0

Using flatMap

let a = [ 1,2,2,3,5,4,2,5,7,9,5,3,8,10 ]
let r = a.enumerated().flatMap { (_ offset: Int, _ element: Int) -> Int? in
    guard offset > 0 else { return nil }
    if element < a[offset-1] && element < a[offset+1] {
        return offset
    }
    return nil
}
0
source

Will a simple end-to-end loop over a range be readable enough and maintainable? You can simply cache intermediate values ​​on repeat, so that you only get access to one element of the array at each iteration. If you want to generalize this to any comparable type, you can implement it as an array extension:

extension Array where Element: Comparable {

    func localMinimums() -> [Int] {
        var minimums = [Int]()

        var currentValue = self[0]
        var nextValue = self[1]
        for index in 1..<(self.count - 1) {
            let previousValue = currentValue
            currentValue = nextValue
            nextValue = self[index + 1]
            if currentValue < nextValue && currentValue < previousValue {
                minimums.append(index)
            }
        }

        return minimums
    }
}

let a = [ 1,2,2,3,5,4,2,5,7,9,5,3,8,10 ]
let r = a.localMinimums()
print(r)
// [6, 11]
0
source

Source: https://habr.com/ru/post/1695306/


All Articles