0

I'm using CoreMotion's GyroData to determine the Z direction of the devise's movement. This returns me an array of doubles. Positive moving forward, negative moving backwards. I'd now like to count how many times the devise moves in one direction. Moving in opposite direction would be one count.

So I'm trying to count how many times the value changes from a positive to a negative value or from a negative to a positive inside an array. If this is the array the count would be 3.

let array = [1, 2, 3, 4, -1, -1, -2, -3, 1, 2, 3, -1, -2]

Is it possible to do this in one line? I feel like I'm totally over complicating things with this code:

var count = 0
var isPositive = false

for (index, value) in array.enumerated() {

  if isPositive == false {
      if value > 0 {
          isPositive = true
          count += 1
      }
   } else {
      if value < 0 
          isPositive = false
          count += 1
      }
   }
}

Thanks!!

Hamish
  • 78,605
  • 19
  • 187
  • 280
robinyapockets
  • 363
  • 5
  • 21

2 Answers2

0

Note: The exact logic about which pairs to count is subject to change, because I'm not exactly sure what you're looking for yet. It should be simple enough to make the proper changes as necessary.

Firstly, I'd clarify what kinds of transitions we're looking for. I'll be looking at transitions from negative numbers (less than 0), to non-negative numbers (0 and all positives). I'll simplify this with the following extension:

extension Integer {
    var isNonNegative: Bool { return !isNegative }
    var isNegative: Bool { return self < 0 }
}

In cases like this, where you're trying to iterate pairs of a Sequence, zip(_:_:) comes in really handy.

let array = [1, 2, 3, 4, -1, -1, -2, -3, 1, 2, 3, -1, -2]
let pairs = zip(array, array.dropFirst(1))
print(Array(pairs))

That results in these pairs:

[(1, 2), (2, 3), (3, 4), (4, -1), (-1, -1), (-1, -2), (-2, -3), (-3, 1), (1, 2), (2, 3), (3, -1), (-1, -2)]

From here, it's a matter of just counting the number of pairs in which the first element (.0) is negative, and the second element (.1) is positive. Like so:

let numRisingEdges = pairs.reduce(0) { count, pair in
    if pair.0.isNegative && pair.1.isNonNegative { return count + 1 }
    else { return count }
}

print(numRisingEdges) // => 1
Alexander
  • 59,041
  • 12
  • 98
  • 151
0

I didn't like my own previous answer so here's a slightly different approach:

    let array = [1, 1, 2, 3, 4, -1, -1, -2, -3, 1, 2, 3, -1, -2]
    func sign(_ i: Int) -> Int {
        switch true {
        case i > 0: return 1
        case i < 0: return -1
        default: return 0
        }
    }
    let result = array.map{sign($0)}.reduce([Int]()) { arr, cur in
        var arr = arr
        if arr.count == 0 {
            arr.append(cur)
        } else if arr.last! != cur {
            arr.append(cur)
        }
        return arr
    }
    print(result.count-1) // 3

The idea is that we maintain arr as a scratchpad of sign changes. But the first entry doesn't count because nothing preceded it, so discount it by subtracting 1 from the overall count of changes.

matt
  • 515,959
  • 87
  • 875
  • 1,141