How to add numbers in a string array? Swift - ios

i have an array, var hoursPlayed = String
they are in a tableView and are all numbers, how would i add the numbers in that array together to get the average of hours played????? in Swift 2

You could use reduce:
let sum= hoursPlayed.reduce(0.0,combine:{$0+Float($1)!})
Basically you are iterating through the array and accumulating all the values. Since it is an array of strings,for simplicity I've force unwrapped to a Float, but you must check for the optional. The reduce function takes a closure as argument with 2 parameters. The dollar sign means take the first and the second and sum them.
Now you can easily divide to the number of elements in the array to have an avergae.
If you are in objC world it would be nice use key value coding and the #avg operator.
[UPDATE]
As Darko posted out the first version won't compile. The error was converting the first argument to a Float, since reduce takes an initial value and I put it as Float there is no need for further conversion.

let array = ["10.0", "30.0"]
if array.count > 0 {
let average = array.reduce(0.0, combine: {$0 + (Double($1) ?? 0.0)}) / Double(array.count)
print(average) // 20.0
}
$0 does not need to be converted because it is guaranteed that it's always Double. $0 is inferred from the initial value, which is declared as 0.0: Double.
array.count has to be checked to guard against a division thru 0.

I'd use a combination of flatMap to convert the strings to Doubles and reduce to add them up:
let doubles = array.flatMap { Double($0) }
let average = doubles.reduce(0.0, combine:+) / Double(doubles.count)
Using flatMap protects you from entries in array that can't be converted to Double If you know they all convert you can simplify it to:
let average = array.map({ Double($0)! }) / Double(array.count)
One final option is to extend Array with an average function if that seems like something you'll be more generally using, and use it in combination with flatMap and/or map:
protocol ArithmeticType {
static func zero() -> Self
func +(lhs:Self, rhs:Self) -> Self
func -(lhs:Self, rhs:Self) -> Self
func /(lhs:Self, rhs:Self) -> Self
func *(lhs:Self, rhs:Self) -> Self
init(_ number:Int)
}
extension Double : ArithmeticType {
static func zero() -> Double {
return 0.0
}
}
extension Array where Element : ArithmeticType {
func average() -> Element {
return reduce(Element.zero(), combine:+) / Element(count)
}
}
let avg = array.flatMap { Double($0) }.average()

Modified Darko's approach, which take in account if String is convertible to Double, or not. For an empty array it returns 0.0
let array = ["10.0", "31.2", "unknown", ""]
func avg(arr: [String])->Double {
let arr = array.flatMap(Double.init)
var avg = 0.0
if arr.count > 0 {
avg = arr.reduce(0.0, combine: + ) / Double(arr.count)
}
return avg
}
let a = avg(array)
print(a) // 20.6

Related

Any magic command to extract an array from array of custom objects?

I have a class like this
class ValueTimestamp {
let value: Double
let timestamp : Double
init(value:Double, timestamp:Double) {
self.value = valuer
self.timestamp = timestamp
}
}
Then I have an array filled with ValueTimestamp objects. Let's call this, myArray.
Now I want to manipulate the array, to extract, for example the elements with values bigger than 10.
Because I am new to swift, I would do this:
// this will create an array with Doubles
let sub = myArray.map($0.value > 10)
var newArray : [ValueTimestamp] = []
for i in 0..< myArray.count {
let newValue = ValueTimestamp.init(value:sub[i], timestamp:myArray[i])
newArray.append(newValue)
}
and now I have newArray that contains the elements from myArray with values bigger than 10.
Is there any magic command using .map, .flatmap or whatever that can do this?
What you looking for is filter method:
public func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]
It takes as parameter closure, which take 1 element and return true if element should be added in resulting array or false if it should be filtered out.
Your code:
let biggerThem10 = myArray.filter { $0.value > 10 }

How do I sort Integer values typed into a TextField in Xcode?

I've just started to do some simple programming with Swift, things like building a simple calculator and stuff like that. Now I would like to create an app that allows me to sort a bunch of integer values which the user is typing into the TextField. Down here is what I've got so far. Could you please tell me where my mistake is?
class ViewController2: UIViewController {
#IBOutlet var randomNumbers: UITextField!
#IBOutlet var finalResult: UITextView!
#IBAction func SortNumbers(_ sender: UIButton) {
let sortedNumbers = Int[randomNumbers.text]
let sortedNubers = sortedNumbers.sort{$1>$2}
finalResult.text = String(sortedNumbers)
}
it's not the best answer you could get, but it might solves your problem:
#IBAction func sortNumbers(_ sender: UIButton) {
let stringWithNumbers = "1 23 12 4 5 12"
let sortedNumbers = stringWithNumbers.components(separatedBy: " ").flatMap { Int($0) }
let sortedNubers = sortedNumbers.sorted { $0 > $1 }
print(sortedNubers.description)
}
You're not converting it into an Int array properly. If we can assume that the input string is a comma-separated list with no spaces:
let sortedNumbers = randomNumbers.text.components(separatedBy: ",").map{ Int($0) ?? 0 }
components splits it into a string array using commas as a reference, and then map converts each element into an Int (and ?? 0 catches any invalid input and prevents it from being an array of optionals).
Also, for the sake of your sanity and that of anyone who might have to read your code later, avoid using nearly-identical variable names like sortedNumbers and sortedNubers. If you need to use multiple variables for the same data, make their differences more descriptive (for instance, the first one should probably be unsortedNumbers in this case).
Your mistake is in trying to treat a single string as if it were an array of numbers. You're missing two steps in there:
Parsing: Take the string that the user has typed and turn it into numbers
Formatting: Take the stored numbers and turn them back into a string to display
Lurking in that first step is the possibility that the user has not actually typed in integers. An approach that just ignores non-integer input would look like:
#IBAction func sortTextAction(_ sender: UIButton) {
guard let text = randomNumbers.text else {
finalResult.text = "" // clear out - no result on empty input
return
}
// Parse String -> [Int]:
// Split into words, then turn words into Ints,
// while discarding non-Int words
let words = text.components(separatedBy: CharacterSet.whitespacesAndNewlines)
let numbers = words
.map({ Int($0) }) // String -> Int?
.flatMap({ $0 }) // discard any nil values
let sorted = numbers.sort()
// Format [Int] -> String: glue the sorted Ints together with a space between each
finalResult.text = sorted
.map({ String(describing: $0 }) // Int -> String: turn 1 into "1"
.joined(separator: " ") // [String] -> String: turn [1, 2, 3] into "1 2 3"
}
}
Lurking behind both of these is localization: What one locale writes as "1,000" might be "1 000" or "1.000" elsewhere. For that, you'd pull in NumberFormatter to handle the conversions in a locale-aware way.

Swift Filtering array elements

I am creating a function that will filter an array, e.g.
x = [10,20,30,40,50]
filter(x,10,20)
output should be 30,40,50.
I am getting an index out of bounds error .
Here's my code:
func filterArray( _ x: [Int], _ nums: Int...) -> [Int]{
var arrayX = x
for i in 0...arrayX.count-1{
for j in 0...nums.count-1 {
if arrayX[i] == nums[j]{//Changed arrayX to x because x was never changed
if let index = arrayX.index(of: nums[j]) {
arrayX.remove(at: index) //error is here
}
else{
}
}
}
}
return arrayX
}
var mArray = [10,20,30,40,50]
filterArray(mArray,10)
The way you are doing it is not correct, you are altering an array while looping through it. When you remove an object from the array, the array count changes but the loop still run using the previously calculated array.count value.
There is a much simpler way of doing this, you just need to combine filter and contains functions together for achieving this:
func filterArray( _ x: [Int], _ nums: Int...) -> [Int]
{
let filteredArray = x.filter({ !nums.contains($0)})
return filteredArray
}
once you remove one element from array its size change, but your loop is still going till previous count that is causing the issue try taking different array to go through the loop and for storing the result and you don't need to find the index its already there, value of 'i' is the index of the element.
You function can be faster if you use a Set.
func filter(list: [Int], _ remove: Int...) -> [Int] {
let removeSet = Set(remove)
return list.filter { removeSet.contains($0) }
}

How to write generic function with array input of floating point convertibles in Swift?

I am taking my first foray into writing generic functions in Swift. What I am trying to do is write a function that takes an array input of any type as long as that type is convertible to a floating point number. I am wondering if I can leverage some of the Swift standard library protocols to do this. Here is a trivial example (I am searching for what to use as ConvertibleToFloatingPointTypeProtocol):
func toDoubleArray<T: ConvertibleToFloatingPointTypeProtocol>(array: [T]) -> [Double] {
var doubleArray = [Double]()
for arrayItem in array {
doubleArray.append(Double(arrayItem))
}
return doubleArray
}
The compiler error I get from this when I try FloatingPointType, etc. is: "Cannot find an initializer for type 'Double' that accepts an argument list of type '(T)'"
Now I know another option is to create my own protocol and then extend the types that I am interested in to adopt it, but this just feels like something that exists right under my nose.
Try FloatLiteralConvertible:
import Darwin
// Swift 2.0
func toDoubleArray<T : FloatLiteralConvertible>(arr : [T]) -> [Double] {
return arr.flatMap { $0 as? Double }
}
// Swift 1.2
func toDoubleArray<T : FloatLiteralConvertible>(arr : [T]) -> [Double] {
var result = [Double]()
for a in arr {
if let d = a as? Double {
result.append(d)
}
}
return result
}
let a = toDoubleArray([1, 2, 3])
let b = toDoubleArray([M_PI, 2 as Int, 3.3])
let c = toDoubleArray(["a", "b", "c"]) // Error, cannot convert [String] to [Double]
let d = toDoubleArray([1, 2, 3, "a"]) // Error, cannot convert [NSObject] to [Double]

what does this line of code in the for statement mean or do?

am studying with a tutorial for a game app and there is a line of code that i didn't understood it looks like it's of type tuple
this is my code:
var algorithmResult = algorithm(value: value)
func rowCheck(#value: Int) -> (location: String, pattern: String)? {
var acceptableFinds = ["011", "101", "110"]
var findFunc = [checkTop, checkBottom, checkMiddleAcross, checkRight, checkMiddleDown, checkLeft, checkDiagLeftRight, checkDiagRightLeft]
for algorithm in findFunc {
var algorithmResult = algorithm(value: value)
if (find(acceptableFinds, algorithmResult.pattern) != nil) {
return algorithmResult
}
}
return nil
}
In:
var algorithmResult = algorithm(value: value)
algorithm represents one element in the findFunc array (as defined in for algorithm in findFunc).
From the names, I'm guessing each of those elements is a function. Those functions are passed value and the result of the function is stored in algorithmResult.
Here's a similar example. Create two functions:
func add(operand : Int) -> Int {
return operand + operand
}
func multiply(operand : Int) -> Int {
return operand * operand
}
Store them in an array:
let funcs = [add, multiply]
Call them in a loop:
for function in funcs {
let x = function(5)
print(x)
}
This prints:
10
25
It applies each function from findFunc array to the value, which was passed to rowCheck function.

Resources