How Convert a *Positive* Number into an Array of Digits in Swift

How convert a *positive* number into an array of digits in Swift

After some searching and some trial and error approach using the Swift REPL, I came up with this

var digits:[Int] = Array(String(number)).map { String($0).toInt()! }

Note that the !is critical

Swift - Distribute an input integer equally to an array of positive & negative numbers

Try using stride(from:through:by:).

  1. Note how the last element (end) in your desired output array is always (input - 1) * 0.5. (You could also do this for the first element, but just flip the sign)
  2. For stride's from, just flip the sign of end
let inputs = [1, 2, 3, 4, 5, 6]
inputs.forEach { input in
let end = Double(input - 1) * 0.5 /// 1.
let output = Array(stride(from: -end, through: end, by: 1)) /// 2.
print("Input: \(input), Output: \(output)")
}

Input: 1, Output: [-0.0]

Input: 2, Output: [-0.5, 0.5]

Input: 3, Output: [-1.0, 0.0, 1.0]

Input: 4, Output: [-1.5, -0.5, 0.5, 1.5]

Input: 5, Output: [-2.0, -1.0, 0.0, 1.0, 2.0]

Input: 6, Output: [-2.5, -1.5, -0.5, 0.5, 1.5, 2.5]

Convert Character to Int in Swift

There is no need to work with characters, but your code to create an
array with the decimal digits of the input number can be greatly
simplified:

var checkSumArray = [Int]()
var tmp = number
while tmp > 0 {
checkSumArray.append(tmp % 10)
tmp /= 10
}
checkSumArray = checkSumArray.reverse()

Make all values of an array negative or change sign

If you need a fast solution for large arrays then you can use
cblas_dscal() ("scalar multiplication, double precision") from the Accelerate framework:

import Accelerate 

var x = [1.0, 2.0, -3.0, 4.0, -5.0]
cblas_dscal(Int32(x.count), -1.0, &x, 1)

print(x) // [-1.0, -2.0, 3.0, -4.0, 5.0]

Remark: There is also cblas_sscal() for Float arrays ("single precision").

Performance comparison: Here is a quite simple performance comparison
of the various methods:

let N = 1_000_000 // # of array elements
let R = 100 // # of repetitions

func test1() {
var x = (0..<N).map { _ in drand48() }
let start = Date()
for _ in 0..<R {
for i in x.indices { x[i] = -x[i] }
}
let time = Date().timeIntervalSince(start)
print("x[i] = -x[i] ", time)
}

func test2() {
var x = (0..<N).map { _ in drand48() }
let start = Date()
for _ in 0..<R {
for i in x.indices { x[i].negate() }
}
let time = Date().timeIntervalSince(start)
print("x[i].negate() ", time)
}

func test3() {
var x = (0..<N).map { _ in drand48() }
let start = Date()
for _ in 0..<R {
x = x.map { -$0 }
}
let time = Date().timeIntervalSince(start)
print("x.map { -$0 } ", time)
}

func test4() {
var x = (0..<N).map { _ in drand48() }
let start = Date()
for _ in 0..<R {
cblas_dscal(Int32(x.count), -1.0, &x, 1)
}
let time = Date().timeIntervalSince(start)
print("cblas_dscal ", time)
}

test1()
test2()
test3()
test4()

Results (on a 3.5 GHz Intel iMac, compiled and run in Release configuration:)


x[i] = -x[i] 0.0492849946022034
x[i].negate() 0.0635690093040466
x.map { -$0 } 0.285757005214691
cblas_dscal 0.0506410002708435

As it turns out, cblas_dscal() has about the same speed as
an explicit loop with x[i] = -x[i] or x[i].negate(), but is
significantly faster than the map() method.

Of course the results may be different on a different hardware, or with
other array sizes.

As usual, start with the method which you are most familiar with and
look for faster methods if it turns out to be performance-critical.

Swift: how to convert readLine() input [-5,20,8...] to an Int array

Here is a one liner to convert the input into an array of integers. Of course you might want to split this up in separate steps if some validation is needed

let numbers = input
.trimmingCharacters(in: .whitespacesAndNewlines)
.dropFirst()
.dropLast()
.split(separator: ",")
.compactMap {Int($0)}

dropFirst/dropLast can be replaced with a replace using a regular expression

.replacingOccurrences(of: "[\\[\\]]", with: "", options: .regularExpression)

Convert positive value to negative value in swift

Just use - operator.

let negativeA = -a

swift maximum consecutive positive numbers

Update: Simpler solution: Split the array into slices of
positive elements, and determine the maximal slice length:

let  numbers = [1,3,4,-1,-2,5,2,-2,-3,-4,5]
let maxConsecutive = numbers.split(whereSeparator: { $0 <= 0 }).map { $0.count }.max()!
print(maxConsecutive) // 3

Old answer:) Using the ideas from Swift running sum:

let  numbers = [1,3,4,-1,-2,5,2,-2,-3,-4,5]

let maxConsecutive = numbers.map({
() -> (Int) -> Int in var c = 0; return { c = $0 > 0 ? c + 1 : 0; return c }
}()).max()!

Here map() maps each array element to the count of consecutive positive
numbers up to the elements position, in this case

[1, 2, 3, 0, 0, 1, 2, 0, 0, 0, 1]

The transformation is created as an "immediately evaluated
closure" to capture a variable c which holds the current number of
consecutive positive numbers. The transformation increments or resets c,
and returns the updated value.

If the array is possibly large then change it to

let maxConsecutive = numbers.lazy.map( ... ).max()!

so that the maximum run length is determined without creating an
intermediate array.

Iterate Array and Count Changes from Negative to Positive (and vice versa)

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

Swift - Convert to absolute value

The standard abs() function works great here:

let c = -8
print(abs(c))
// 8


Related Topics



Leave a reply



Submit