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:)
.
- 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) - For
stride
'sfrom
, just flip the sign ofend
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
Zposition of Sknode Relative to Its Parent
How to Skip Iterations of a For-In Loop (Swift 3)
Swift Cannot Assign to Self in a Class Init Method
Implementing Swift Protocol Methods in a Base Class
Showing Notification Banner on MAC with Swift
How to Cast [Int8] to [Uint8] in Swift
Non-Modular Headers of Openssl Library When Using Modulemap for Swift Framework
C-Style Uninitialized Pointer Passing in Apple Swift
Differences Between Filtering Realm with Nspredicate and Block
Swiftui Share Sheet Crashes iPad
Swiftui Editbutton Action on Done
How to Sum the Numbers(Int16) of Stored Core Data - Swift 3
Swift Error with Generic Array
How to Print Escape Sequence Characters in Swift
Textfield in Swiftui Loses Focus When I Enter a Character
How to Set Alignment for Wkinterface Label Using Setattributedtext