swift: average consecutive positive number - arrays

We have an array, for example:
let numbers = [-1.0,1.0,3.0,4.0,-1.0,-2.0,2.0]
We know how to get maximum consecutive positive number:
let pos = numbers.map({ () -> (Double) -> Int in var c = 0; return { c = $0 > 0 ? c + 1 : 0; return c } }())
// [0, 1, 2, 3, 0, 0, 1]
let maxConsecutivePos = pos.max()!
//3
How can we find average consecutive positive number the same way, using closures and pos array in our case? For this example, we divide sum (3 + 1) by 2 -> 2 is expected output.

A possible solution: Split the array into slices of consecutive
positive numbers, then compute the average slice length:
let numbers = [-1.0, 1.0, 3.0, 4.0, -1.0, -2.0, 2.0]
let slices = numbers.split(whereSeparator: { $0 <= 0 })
// --> [ArraySlice([1.0, 3.0, 4.0]), ArraySlice([2.0])]
let avg = Double(slices.reduce(0, { $0 + $1.count })) / Double(slices.count)
print(avg) // 2.0

You basically compare each element with the next one and check, if it the next one is less. If it is less, then it's a max and you use it to calculate the average.
let array = [0, 1, 2, 3, 0, 0, 1]
func maxConsAvg(array: [Int]) -> Double? {
guard array.count > 1 else {
return array.first.flatMap({ Double($0) })
}
let array = array + [0]
let maxs = zip(array.dropLast(), array.dropFirst())
.flatMap { (first, second) -> Int? in
return first > second ? first : nil
} //[3, 1]
return Double(maxs.reduce(0, +)) / Double(maxs.count)
}
maxConsAvg(array: array) //2

Related

How to get the sum of values in array in swift

I have an array with elements like a = [5,6,8,9,2,6,8]. So when I do the first iteration I skip the first index and then add the remaining elements in the array and if I do the second iteration I skip the second element and then add the remaining elements. ex: for the second iteration I skip the second element and then add the remaining elements as 5 + 8 + 9 + 2 + 6 + 8 = 38 like this I want to add the elements and find the highest sum of the elements and minimum sum of the elements. How to do that in swift?
Try this:
let array: [Int] = [1, 2, 3, 4, 5]
var min: Int!
var max: Int!
for (index, _) in array.enumerated() {
var auxArray = array
auxArray.remove(at: index)
let sum = auxArray.reduce(0, +)
if min == nil || max == nil {
min = sum
max = sum
} else if sum < min {
min = sum
} else if sum > max {
max = sum
}
}
print("MIN: \(min!), MAX: \(max!)")
You can do it with one iteration
let a = [5,6,8,9,2,6,8]
var sum = 0
var smallestNumber = a[0]
var largestNumber = a[0]
for number in a {
sum += number
if number < smallestNumber {
smallestNumber = number
}
if number > largestNumber {
largestNumber = number
}
}
let smallestSum = sum - largestNumber
let largestSum = sum - smallestNumber

Index out of range: Mapping the output of a 3-input function to a 3-dimentional floating-point array in Swift 4

I want to set the elements in a mutable 3d array of Doubles to the output of a 3-input function, f(), for the position of that element in the array ([a][n][b]), then print the array.
//3-input function must input and output doubles. This function is an example.
func f(a: Double, n: Double, b: Double) -> Double {
return a * n * b
}
//Size of array: 7*7*7
let aMax = 6
let nMax = 6
let bMax = 6
//Define mutable array; I don't know if I need to initialize array "points".
var points = [[[Double]]]()
//I don't know if I should use ".append" or "=".
for a in 0...aMax {
for n in 0...nMax {
for b in 0...bMax {
points[a][n][b] = f(a: Double(a), n: Double(n), b: Double(b)) //Changing element at position results in "fatal error: Index out of range".
}
}
}
print(points)
The problem is that after doing:
var points = [[[Double]]]()
points is completely empty. So any attempt to access any of the indexes results in the "Index out of range" error.
Since you are going to fill the whole thing, initializing the three dimensions using Array(repeating:count:).
var points = Array(repeating: Array(repeating: Array(repeating: 0.0, count: bMax + 1), count: nMax + 1), count: aMax + 1)
Now the rest of your code will work.
You can try this , for an array declared like this [[[Double]]] you can use append only but for assigning and indexing it you must first init it like this
//Size of array: 7*7*7
let aMax = 7
let nMax = 7
let bMax = 7
//Define mutable array; I don't know if I need to initialize array "points".
var points = [[[Double]]](repeating: [[Double]](repeating: [Double](repeating: 0, count: bMax), count: nMax), count: aMax)
//I don't know if I should use ".append" or "=".
for a in 0..<aMax {
for n in 0..<nMax {
for b in 0..<bMax {
points[a][n][b] = (f(a: Double(a), n: Double(n), b: Double(b))) //Changing element at position results in "fatal error: Index out of range".
}
}
}
print(points)
You can declare and initialize a "3D" array in a single shot, using Array.map(_:):
let (aCount, nCount, bCount) = (8, 8, 8)
let points: [[[Double]]] = (0 ..< aCount).map { aInt in
let a = Double(aInt)
return (0 ..< nCount).map { nInt in
let n = Double(nInt)
return (0 ..< bCount).map { bInt in
return f(a: a, n: n, b: Double(bInt))
}
}
}

Get median of array

I have an array that looks like this:
let arr = [1,2,3,4,5,6,7,8,9]
I know you can get min and max by:
let min = arr.min()
let max = arr.max()
But how do you get the median?
To get the median you can use the following:
let median = arr.sorted(by: <)[arr.count / 2]
In your case it will return 5.
As #Nirav pointed out [1,2,3,4,5,6,7,8] will return 5 but should return 4.5.
Use this instead:
func calculateMedian(array: [Int]) -> Float {
let sorted = array.sorted()
if sorted.count % 2 == 0 {
return Float((sorted[(sorted.count / 2)] + sorted[(sorted.count / 2) - 1])) / 2
} else {
return Float(sorted[(sorted.count - 1) / 2])
}
}
Usage:
let array = [1,2,3,4,5,6,7,8]
let m2 = calculateMedian(array: array) // 4.5
The median is defined as the number in the middle of the sequence. If there is not one middle number, then it's the average of the two middle numbers.
extension Array where Element == Int {
func median() -> Double {
let sortedArray = sorted()
if count % 2 != 0 {
return Double(sortedArray[count / 2])
} else {
return Double(sortedArray[count / 2] + sortedArray[count / 2 - 1]) / 2.0
}
}
}
Note that if the array is empty, the median is undefined. So a safe median function returns an optional, just like the min() and max() built-in methods do.
extension Array where Element == Int {
func median() -> Double? {
guard count > 0 else { return nil }
let sortedArray = self.sorted()
if count % 2 != 0 {
return Double(sortedArray[count/2])
} else {
return Double(sortedArray[count/2] + sortedArray[count/2 - 1]) / 2.0
}
}
}
With that defined, you can write:
if let median = arr.median() {
// do something
}
If someone (like me) likes two*-liners:
let sorted = arr.sorted(by: <)
let median = Double(sorted[arr.count/2] + sorted.reversed()[arr.count/2])/2.0
Algorithms that use sorted take O(n log n) time. That's typically not a problem for 9 numbers, but if your array is large, use an algorithm that completes in O(n) time. An example is this k-th largest element algorithm. It recursively partitions the array, but doesn’t have to go through all the work to sort it, so it’s much faster.

Inefficient parsing of Vertex and Index data, looking for more efficient methods

I wrote a method to parse an array containing vertex data. The goal of the method was to produce a new array of unique vertices and a new index from that data.
This is the struct I used to store the vertices in the array.
struct Vertex: Hashable {
var x, y, z,
nx, ny, nz,
s, t: Float
var hashValue: Int {
return "\(self.x),\(self.y),\(self.z),\(self.nx),\(self.ny),\(self.nz),\(self.s),\(self.t),".hashValue
}
static func ==(lhs: Vertex, rhs: Vertex) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
And this is the method I used to create the array of unique vertices and new index. The first argument of the method takes an array with the vertex data already ordered by the original index.
func makeVertexIndex(_ array: [Float]) -> ([Vertex], [Int]) {
var counter = 0
var indexCounter = 0
var holder = [Float]()
var vertices = [Vertex]()
var index = [Int]()
for i in array {
counter += 1
if counter == 8 {
counter = 0
holder.append(i)
let vertex = Vertex(x: holder[0], y: holder[1], z: holder[2],
nx: holder[3], ny: holder[4], nz: holder[5],
s: holder[6], t: holder[7])
if vertices.contains(vertex) {
guard let match = vertices.index(of: vertex) else { continue }
index.append(match)
} else {
vertices.append(vertex)
index.append(indexCounter)
indexCounter += 1
}
holder.removeAll()
} else {
holder.append(i)
}
}
return (vertices, index)
}
I was able to successfully parse lower triangle count meshes, but when I try to run this on higher triangle count meshes it took over an hour to run.
I'm pretty new to coding, Swift is my first language, but I suspect it shouldn't take this long to do this task and I probably just wrote my method really inefficiently or maybe there's a completely different way I could approach this problem.
Anyhow I'd appreciate any help I could get. Thanks for reading.
Update 1:
I re-wrote my method to create the vertex array first then change to it to a set to make the values unique and back to an array then ran it through the vertexArray loop looking for matches in the unique vertices array. This version of the method cut the process time from 21 seconds on my test mesh to about 12 seconds.
func makeVertexIndex(_ array: [Float]) -> ([Vertex], [Int]) {
var counter = 0
var holder = [Float]()
var vertexArray = [Vertex]()
var vertices = [Vertex]()
var index = [Int]()
for i in array {
counter += 1
if counter == 8 {
counter = 0
holder.append(i)
let vertex = Vertex(x: holder[0], y: holder[1], z: holder[2],
nx: holder[3], ny: holder[4], nz: holder[5],
s: holder[6], t: holder[7])
vertexArray.append(vertex)
holder.removeAll()
} else {
holder.append(i)
}
}
let vertexSet = Set(vertexArray)
vertices = Array(vertexSet)
for v in vertexArray {
guard let match = vertices.index(of: v) else { continue }
index.append(match)
}
return (vertices, index)
}
Update 2:
Here are my updated struct and method after implementing some of the recommended solutions.
Struct:
struct Vertex: Hashable {
var x, y, z,
nx, ny, nz,
s, t: Float
var hashValue: Int {
return "\(self.x),\(self.y),\(self.z),\(self.nx),\(self.ny),\(self.nz),\(self.s),\(self.t)".hashValue
}
static func ==(lhs: Vertex, rhs: Vertex) -> Bool {
return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z) && (lhs.nx == rhs.nx) &&
(lhs.ny == rhs.ny) && (lhs.nz == rhs.nz) && (lhs.s == rhs.s) && (lhs.t == rhs.t)
}
}
Method:
func makeVertexIndex(_ array: [Float]) -> ([Vertex], [Int]) {
var vertexArray = [Vertex]()
vertexArray.reserveCapacity(array.count / 8)
var vertices = [Vertex]()
var index = [Int]()
// Creating an array of Vertex from an array containing
// position/normal/texcoord in correct order.
for i in stride(from: 0, to: array.count, by: 8) {
let vertex = Vertex(x: array[i], y: array[i + 1], z: array[i + 2],
nx: array[i + 3], ny: array[i + 4], nz: array[i + 5],
s: array[i + 6], t: array[i + 7])
vertexArray.append(vertex)
}
// Making the Vertex array unique by converting to set and back to array.
let vertexSet = Set(vertexArray)
vertices = Array(vertexSet)
// Making new index by finding the matching vertex in the
// unique vertex array and adding that array index to the new index
for v in vertexArray {
guard let match = vertices.index(of: v) else { continue }
index.append(match)
}
return (vertices, index)
}
After trying out various parts of the recommended solutions the method was able to process a model with 70K triangles in 13 minutes, previously it took over an hour and a half.
So this was a huge improvement, appreciate all the solutions so far, going to keep this open for maybe a day or two to see if any other recommendations come.
Is there a particular reason why your == code compares hashes rather than each property? i.e.
static func ==(lhs: Vertex, rhs: Vertex) -> Bool {
return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z) &&
(lhs.nx == rhs.nx) && ...etc
}
Then if lhs.x is not equal to rhs.x, the code will fail quickly and move on to the next. Currently you're having to create a hash value again and again. Alternatively, you could speed up your current code by calculating the hash once in the constructor (and, say, making all the properties private(set) like in the simplified example below).
struct Vertex {
private(set) var x, y: Float
let hash: Int
init(x: Float, y: Float) {
self.x = x
self.y = y
hash = "\(x),\(y)".hashValue
}
static func ==(lhs: Vertex, rhs: Vertex) -> Bool {
return lhs.x == rhs.x
}
}
let vertex = Vertex(x: 1.0, y: 2.0)
print(vertex.hash)
It looks like you're trying to end up with a new set of Vertices, and a set of indices. If the new set of vertices contains a duplicate, remove that from the list of vertices, and double the index of the duplicate. Judging from your first function. Your second only added an index when there was a match. Which did you mean?
From the first.. if you have V1 V2 V3 V4, and V4 = V1, you want indices [0,0,1,2].
Is this correct? I would clean that up by iterating over the float array 8 at a time, then determine if there are duplicates, if so, figure out which are duplicates and then create your final two arrays. Here's my take..
func makeVertexIndex(_ array: [Float]) -> ([Vertex], [Int]) {
var newVertices = [Vertex]()
for i in stride(from: 0, to: array.count, by: 8) {
newVertices.append(Vertex(x: array[i], y: array[i + 1], z: array[i + 2],
nx: array[i + 3], ny: array[i + 4], nz: array[i + 5],
s: array[i + 6], t: array[i + 7]))
}
if newVertices.count > Set(newVertices).count {
var uniqueVertices = [Vertex]()
var indices = [Int]()
var vertexIndex = [Vertex: Int]()
var count = 0
for vertex in newVertices {
if let existingVertex = vertexIndex[vertex] {
indices.append(existingVertex)
} else {
vertexIndex[vertex] = count
uniqueVertices.append(vertex)
count += 1
}
}
return (uniqueVertices, indices.sorted())
} else {
return (newVertices, [Int](0..<newVertices.count))
}
}

Finding sum of elements in Swift array

What is the easiest (best) way to find the sum of an array of integers in swift?
I have an array called multiples and I would like to know the sum of the multiples.
This is the easiest/shortest method I can find.
Swift 3 and Swift 4:
let multiples = [...]
let sum = multiples.reduce(0, +)
print("Sum of Array is : ", sum)
Swift 2:
let multiples = [...]
sum = multiples.reduce(0, combine: +)
Some more info:
This uses Array's reduce method (documentation here), which allows you to "reduce a collection of elements down to a single value by recursively applying the provided closure". We give it 0 as the initial value, and then, essentially, the closure { $0 + $1 }. Of course, we can simplify that to a single plus sign, because that's how Swift rolls.
Swift 3+ one liner to sum properties of objects
var totalSum = scaleData.map({$0.points}).reduce(0, +)
Where points is the property in my custom object scaleData that I am trying to reduce
In Swift 4 You can also constrain the sequence elements to Numeric protocol to return the sum of all elements in the sequence as follow
extension Sequence where Element: Numeric {
/// Returns the sum of all elements in the collection
func sum() -> Element { return reduce(0, +) }
}
edit/update:
Xcode 10.2 • Swift 5 or later
We can simply constrain the sequence elements to the new AdditiveArithmetic protocol to return the sum of all elements in the collection
extension Sequence where Element: AdditiveArithmetic {
func sum() -> Element {
return reduce(.zero, +)
}
}
Xcode 11 • Swift 5.1 or later
extension Sequence where Element: AdditiveArithmetic {
func sum() -> Element { reduce(.zero, +) }
}
let numbers = [1,2,3]
numbers.sum() // 6
let doubles = [1.5, 2.7, 3.0]
doubles.sum() // 7.2
To sum a property of a custom object we can extend Sequence to take a predicate to return a value that conforms to AdditiveArithmetic:
extension Sequence {
func sum<T: AdditiveArithmetic>(_ predicate: (Element) -> T) -> T { reduce(.zero) { $0 + predicate($1) } }
}
Usage:
struct Product {
let id: String
let price: Decimal
}
let products: [Product] = [.init(id: "abc", price: 21.9),
.init(id: "xyz", price: 19.7),
.init(id: "jkl", price: 2.9)
]
products.sum(\.price) // 44.5
Swift3 has changed to :
let multiples = [...]
sum = multiples.reduce(0, +)
Swift 4 example
class Employee {
var salary: Int = 0
init (_ salary: Int){
self.salary = salary
}
}
let employees = [Employee(100),Employee(300),Employee(600)]
var sumSalary = employees.reduce(0, {$0 + $1.salary}) //1000
This also works:
let arr = [1,2,3,4,5,6,7,8,9,10]
var sumedArr = arr.reduce(0, combine: {$0 + $1})
print(sumedArr)
The result will be: 55
Swift 3
If you have an array of generic objects and you want to sum some object property then:
class A: NSObject {
var value = 0
init(value: Int) {
self.value = value
}
}
let array = [A(value: 2), A(value: 4)]
let sum = array.reduce(0, { $0 + $1.value })
// ^ ^
// $0=result $1=next A object
print(sum) // 6
Despite of the shorter form, many times you may prefer the classic for-cycle:
let array = [A(value: 2), A(value: 4)]
var sum = 0
array.forEach({ sum += $0.value})
// or
for element in array {
sum += element.value
}
Swift 3, 4, and 5
Using reduce:
let totalAmount = yourTransactionsModelArray.reduce(0) { $0 + $1.amount}
Old fashioned way for understanding purposes:
for (var i = 0; i < n; i++) {
sum = sum + Int(multiples[i])!
}
//where n = number of elements in the array
A possible solution: define a prefix operator for it.
Like the reduce "+/" operator as in APL (e.g. GNU APL)
A bit of a different approach here.
Using a protocol en generic type allows us to to use this operator on Double, Float and Int array types
protocol Number
{
func +(l: Self, r: Self) -> Self
func -(l: Self, r: Self) -> Self
func >(l: Self, r: Self) -> Bool
func <(l: Self, r: Self) -> Bool
}
extension Double : Number {}
extension Float : Number {}
extension Int : Number {}
infix operator += {}
func += <T:Number> (inout left: T, right: T)
{
left = left + right
}
prefix operator +/ {}
prefix func +/ <T:Number>(ar:[T]?) -> T?
{
switch true
{
case ar == nil:
return nil
case ar!.isEmpty:
return nil
default:
var result = ar![0]
for n in 1..<ar!.count
{
result += ar![n]
}
return result
}
}
use like so:
let nmbrs = [ 12.4, 35.6, 456.65, 43.45 ]
let intarr = [1, 34, 23, 54, 56, -67, 0, 44]
+/nmbrs // 548.1
+/intarr // 145
(updated for Swift 2.2, tested in Xcode Version 7.3)
Swift 3.0
i had the same problem, i found on the documentation Apple this solution.
let numbers = [1, 2, 3, 4]
let addTwo: (Int, Int) -> Int = { x, y in x + y }
let numberSum = numbers.reduce(0, addTwo)
// 'numberSum' == 10
But, in my case i had a list of object, then i needed transform my value of my list:
let numberSum = self.list.map({$0.number_here}).reduce(0, { x, y in x + y })
this work for me.
another easy way of getting it done:
let sumOfMultiples = ar.reduce(0) { x, y in x + y }
print(sumOfMultiples)
Keep it simple...
var array = [1, 2, 3, 4, 5, 6, 7, 9, 0]
var n = 0
for i in array {
n += i
}
print("My sum of elements is: \(n)")
Output:
My sum of elements is: 37
For me, it was like this using property
let blueKills = match.blueTeam.participants.reduce(0, { (result, participant) -> Int in
result + participant.kills
})
#IBOutlet var valueSource: [MultipleIntBoundSource]!
private var allFieldsCount: Int {
var sum = 0
valueSource.forEach { sum += $0.count }
return sum
}
used this one for nested parameters
For sum of elements in array of Objects
self.rankDataModelArray.flatMap{$0.count}.reduce(0, +)

Resources