Cannot get the right average value of a couple of numbers - ios

func averageOf(numbers: Int...) -> Float {
var sum = 0
var i = 1
for number in numbers {
sum += number
i++
}
return Float(sum)/Float(i)
}
averageOf(1,2,3,4,4)
return value
2.33333325386047
Im new to Swift and run this code in the playground. The return value is not right, but I cannot find where is wrong, since the sum is 14 and the i is 5.

Start with i=0 instead of one. Since you're incrementing i after each number, i is ending up as 6 in your example instead of 5.

Related

Get the last X non-empty rows of a range in Google Sheets

I have a range like in the following image:
Where the top headers represent the months of the year (1-12) and the left column represents the days in a month (1 to 28/29/30/31).
I would like to perform a SUM function over the last 30 days of my range such that it starts counting from the last non-empty value and goes up until it reaches the first value of that column, and then if there are still days to count, goes to the previous month and starts counting from its last value.
For example, in the image if I wanted the sum of the values of the last 6 cells of the range, it would sum up 16, 12, 8, 4, 4 and 15.
I've tried adapting the solution to a similar problem as outlined here, but I haven't been able to make it work so far.
Using the solution to this question about iterating over a range using Google Script, I was able to devise a working script.
The script will iterate a specific number of cells backward from the last cell of a range (it iterates all rows of a column before moving to the previous column), skips empty cells, and returns the sum of the values encountered into a new cell.
function sumOfLast30() {
var range = SpreadsheetApp.getActiveSheet().getRange("A1:B2");
var numRows = range.getNumRows(); // 2
var numCols = range.getNumColumns(); // 2
var counter = 0;
var counterMax = 2; // this determines how many cells get counted
var sumValues = 0;
for (var i = numCols; i > 0; i--)
{
if (counter == counterMax) {
break;
}
for (var j = numRows; j > 0; j--) {
var selectedValue = range.getCell(j,i).getValue();
if (selectedValue != "")
{
sumValues = sumValues + selectedValue;
counter++;
if (counter == counterMax)
{
break;
}
}
}
}
var target = SpreadsheetApp.getActiveSheet().getRange("C3");
target.setValue(sumValues);
}

Randomly choosing an item from a Swift array without repeating

This code picks a random color from a array of pre-set colors. How do I make it so the same color doesn't get picked more than once?
var colorArray = [(UIColor.redColor(), "red"), (UIColor.greenColor(), "green"), (UIColor.blueColor(), "blue"), (UIColor.yellowColor(), "yellow"), (UIColor.orangeColor(), "orange"), (UIColor.lightGrayColor(), "grey")]
var random = { () -> Int in
return Int(arc4random_uniform(UInt32(colorArray.count)))
} // makes random number, you can make it more reusable
var (sourceColor, sourceName) = (colorArray[random()])
Create an array of indexes. Remove one of the indexes from the array and then use that to fetch a color.
Something like this:
var colorArray = [
(UIColor.redColor(), "red"),
(UIColor.greenColor(), "green"),
(UIColor.blueColor(), "blue"),
(UIColor.yellowColor(), "yellow"),
(UIColor.orangeColor(), "orange"),
(UIColor.lightGrayColor(), "grey")]
var indexes = [Int]();
func randomItem() -> UIColor
{
if indexes.count == 0
{
print("Filling indexes array")
indexes = Array(0..< colorArray.count)
}
let randomIndex = Int(arc4random_uniform(UInt32(indexes.count)))
let anIndex = indexes.removeAtIndex(randomIndex)
return colorArray[anIndex].0;
}
The code above creates an array indexes. The function randomItem looks to see if indexes is empty. if it is, it populates it with index values ranging from 0 to colorArray.count - 1.
It then picks a random index in the indexes array, removes the value at that index in the indexes array, and uses it to fetch and return an object from your colorArray. (It doesn't remove objects from the colorArray. It uses indirection, and removes objects from the indexesArray, which initially contains an index value for each entry in your colorArray.
The one flaw in the above is that after you fetch the last item from indexArray, you populate it with a full set of indexes, and it's possible that the next color you get from the newly repopulated array will be the same as the last one you got.
It's possible to add extra logic to prevent this.
based on the fact, that arc4random_uniform generate not only random, but also uniformly distributed numbers
import Foundation // arc4random_uniform
class Random {
var r:UInt32
let max: UInt32
init(max: UInt32) {
self.max = max
r = arc4random_uniform(max)
}
var next: UInt32 {
var ret: UInt32
repeat {
ret = arc4random_uniform(max)
} while r == ret
r = ret
return r
}
}
// usage example
let r = Random(max: 5)
for i in 0..<10 {
print(r.r, r.next) // there will never be a pair of the same numbers in the
// generated stream
}
/*
2 4
4 0
0 3
3 0
0 3
3 4
4 1
1 3
3 4
4 3
*/
simple test for different k and stream length of one milion
class Random {
var r:UInt32
let max: UInt32
init(max: UInt32) {
self.max = max
r = arc4random_uniform(max)
}
var next: (UInt32, Int) {
var i = 0
var ret: UInt32
repeat {
ret = arc4random_uniform(max)
i += 1
} while r == ret
r = ret
return (r,i)
}
}
for k in 3..<16 {
let r = Random(max: UInt32(k))
var repetition = 0
var sum = 0
for i in 0..<1000000 {
let j = r.next
repetition = max(repetition, j.1)
sum += j.1
}
print("maximum of while repetition for k:", k, "is", repetition, "with average of", Double(sum) / Double(1000000) )
}
prints
maximum of while repetition for k: 3 is 15 with average of 1.499832
maximum of while repetition for k: 4 is 12 with average of 1.334008
maximum of while repetition for k: 5 is 9 with average of 1.250487
maximum of while repetition for k: 6 is 8 with average of 1.199631
maximum of while repetition for k: 7 is 8 with average of 1.167501
maximum of while repetition for k: 8 is 7 with average of 1.142799
maximum of while repetition for k: 9 is 8 with average of 1.124096
maximum of while repetition for k: 10 is 6 with average of 1.111178
maximum of while repetition for k: 11 is 7 with average of 1.099815
maximum of while repetition for k: 12 is 7 with average of 1.091041
maximum of while repetition for k: 13 is 6 with average of 1.083582
maximum of while repetition for k: 14 is 6 with average of 1.076595
maximum of while repetition for k: 15 is 6 with average of 1.071965
finaly, here is more Swifty and functional approach based on the same idea
import Foundation
func random(max: Int)->()->Int {
let max = UInt32(max)
var last = arc4random_uniform(max)
return {
var r = arc4random_uniform(max)
while r == last {
r = arc4random_uniform(max)
}
last = r
return Int(last)
}
}
let r0 = random(8)
let r1 = random(4)
for i in 0..<20 {
print(r0(), terminator: " ")
}
print("")
for i in 0..<20 {
print(r1(), terminator: " ")
}
/*
4 5 4 3 4 0 5 6 7 3 6 7 5 4 7 4 7 2 1 6
0 3 0 1 0 2 3 1 2 0 1 0 1 0 1 3 0 3 0 2
*/
Fill an array with the colors and shuffle it with a Fisher-Yates shuffle. Then use the element at an end, remove it, and insert it at a random position at least n positions from the end.
For example, say my array has 10 elements. I shuffle it and take the last. I want at least 2 values to be chosen before I see it again so I generate a random position in the range 0...8 and insert it there.
var colorArray = [
(UIColor.redColor() , "red" ),
(UIColor.greenColor() , "green" ),
(UIColor.blueColor() , "blue" ),
(UIColor.yellowColor() , "yellow"),
(UIColor.orangeColor() , "orange"),
(UIColor.lightGrayColor(), "grey" )].shuffle() // shuffle() is from my link above
let spacing = 2 // Pick at least 2 colors before we see it again
if let randomColor = colorArray.popLast() {
colorArray.insert(randomColor,
atIndex: Int(arc4random_uniform(UInt32(colorArray.count - spacing))))
}
One case, described here: https://github.com/dimpiax/GenericSequenceType
Another is functional:
func getRandomItem<T>(arr: [T]) -> (unique: Bool) -> T {
var indexes: [Int]!
return { value in
let uniqIndex: Int
if value {
if indexes?.isEmpty != false {
indexes = [Int](0.stride(to: arr.count, by: 1))
}
uniqIndex = indexes.removeAtIndex(Int(arc4random_uniform(UInt32(indexes.count))))
}
else {
uniqIndex = Int(arc4random_uniform(UInt32(arr.count)))
}
return arr[uniqIndex]
}
}
let generate = getRandomItem(colorArray)
generate(unique: true).0 // greenColor
generate(unique: true).0 // redColor
generate(unique: true).0 // lightGrayColor
Try it it's work for me and 100% tested
let arrString = ["1","2","3","4","5","6"]
var selectedIndix = -1
#IBAction func btnClick(_ sender: Any) {
let randomElementIndex = randomElementString()
}
Call this function when button clicked
func randomElementString() -> Int{
let randomm = Int(arc4random_uniform(UInt32(arrString.count)))
if selectedIndix == randomm{
return randomElementString()
}else{
selectedIndix = randomm
return randomm
}
}
OUTPUT:-
5121242316513126
How about running a while loop with the condition:
while(self.source.backgroundColor == sourceColor) {
// get a new random sourceColor
}
This will keep looping until a new random color has been selected.
edit
Additional Note: The point was the while loop. There are ways to safeguard from an infinite loop, it's up to the coder to find the right solution. I don't think SO is a place to write other's code but instead to offer suggestions .. mine is a start.
But since my answer was given such a negative rating, i'll push instead of nudge in the right direction.
The other answers are unnecessarily bloated. And? The one I offered above offers a less than desirable time complexity. So, here's my new answer (in meta code):
// array of all background colors
var arrayOfColors = [..]
// get a random index
var randomIndex = arc4random(size of arrayOfColors)
// select new background color
var newBGColor = arrayOfColors[randomIndex]
// old background color
var oldBGColor = self.source.backgroundColor
// remove new color from array (so that it's excluded from choices next time)
arrayOfColors.removeAtIndex(randomIndex)
// set the new color to the background
self.source.backgroundColor = newBGColor
// add current color back into the pool of potential colors
arrayOfColors.addObject(oldBGColor)

How to generate a 4 digit random number with unique digits?

Like: 0123, 0913, 7612
Not like: 0000, 1333, 3499
Can it be done with arcRandom() in swift? Without array or loop?
Or If that impossible, how it be done with arcRandom() in any way ?
You just want to shuffle the digits and pick the number you want.
Start with Nate Cook's Fischer-Yates shuffle code.
// Start with the digits
let digits = 0...9
// Shuffle them
let shuffledDigits = digits.shuffle()
// Take the number of digits you would like
let fourDigits = shuffledDigits.prefix(4)
// Add them up with place values
let value = fourDigits.reduce(0) {
$0*10 + $1
}
var fourUniqueDigits: String {
var result = ""
repeat {
// create a string with up to 4 leading zeros with a random number 0...9999
result = String(format:"%04d", arc4random_uniform(10000) )
// generate another random number if the set of characters count is less than four
} while Set<Character>(result.characters).count < 4
return result // ran 5 times
}
fourUniqueDigits // "3501"
fourUniqueDigits // "8095"
fourUniqueDigits // "9054"
fourUniqueDigits // "4728"
fourUniqueDigits // "0856"
Swift Code - For Generation of 4 digit
It gives number between 1000 and 9999.
func random() -> String {
var result = ""
repeat {
result = String(format:"%04d", arc4random_uniform(10000) )
} while result.count < 4 || Int(result)! < 1000
print(result)
return result
}
Please Note - You can remove this Int(result)! < 1000 if you want numbers like this - 0123, 0913

Sum elements of an array of objects in a for loop in swift: Sum variable not retaining value?

I wrote what I thought was a basic function to sum up values of an array and calculate an amount left in budget. I use a for loop to sum the elements of an array, then subtract this value from the budget. However, for some reason the value of sum updates properly in the for loop, but the sum value out of the for loop is always zero. In the below the println "Sum in the loop" is correct, but the println "Sum is" always equals 0. dataModel.spendingDataDisplay is an array of objects. Thanks for any help.
func amountLeftToSpend ()->Double {
var sum:Double = 0.0
for spendingItem in dataModel.spendingDataDisplay {
var sum = spendingItem.amountSpent + sum
println("Spending Item .amountSpent\(spendingItem.amountSpent)")
println("Sum in the loop is \(sum)")
}
println("Sum is \(sum)")
let amountLeftInBudget = dataModel.settingsData.weeklyBudget - sum
println("Amount Left in Budget is \(amountLeftInBudget)")
return amountLeftInBudget
}
As others have pointed out, you have two sum variables. So you could solve this by eliminating the inner var reference:
var sum:Double = 0.0
for spendingItem in dataModel.spendingDataDisplay {
sum += spendingItem.amountSpent
}
Alternatively, if spendingDataDisplay is a Swift array, you can also use the reduce method:
let sum = dataModel.spendingDataDisplay.reduce(0.0) { $0 + $1.amountSpent }
var sum:Double = 0.0
for spendingItem in dataModel.spendingDataDisplay {
var sum = spendingItem.amountSpent + sum
on the third line you redeclare the variable sum. It should read:
var sum:Double = 0.0
for spendingItem in dataModel.spendingDataDisplay {
sum = spendingItem.amountSpent + sum
Im not sure it does actually work either...
Interestingly we only get the compiler warning outside of its function context
It looks like you're updating the local variable sum inside the for loop, and not the variable declared as a Double outside the loop. That's why the "Sum is" is always 0. I'm not actually sure how the "Sum in the loop" is correct given your code, but I'm not very good with Swift.
I think you need to change
var sum = spendingItem.amountSpent + sum
to just sum += spendingItem.amountSpent
You can use reduce function to avoid that kind of errors.
func amountLeftToSpend ()->Double {
let sum = reduce(dataModel.spendingDataDisplay, 0.0) { $0 + $1.amountSpeed }
println("Sum is \(sum)")
let amountLeftInBudget = dataModel.settingsData.weeklyBudget - sum
println("Amount Left in Budget is \(amountLeftInBudget)")
return amountLeftInBudget
}

Convert Character to Int in Swift

I'm working on a project which includes verifying the checksum of an Int input with the Damm Algorithm. I've managed to create a the operational table and my method for accessing the value in the table involves passing an interim value and a digit to pass in as the column value.
ex.
self.tableToUse[interim,checkSumArray[i]]
Unfortunately, I've run into a snag when I'm trying to pass the digits from my input into the the get/set method where I cannot find a way to convert the Characters into Ints.
func encode(number: Int) -> Int{
var checkSumArray = [Int]()
if number > 99999999 {
println("number is too large")
return 0
}
else if number < 0 {
println("invalid input")
return 0
}
else {
checkSumArray.append(number%(10))
checkSumArray.append((number%(100)-checkSumArray[0])/10)
checkSumArray.append((number%(1000)-checkSumArray[1])/100)
checkSumArray.append((number%(10000)-checkSumArray[2])/1000)
checkSumArray.append((number%(100000)-checkSumArray[3])/10000)
checkSumArray.append((number%(1000000)-checkSumArray[4])/100000)
checkSumArray.append((number%(10000000)-checkSumArray[5])/1000000)
checkSumArray.append((number%(100000000)-checkSumArray[6])/10000000)
checkSumArray = checkSumArray.reverse()
var interim: Int = 0
for i in 0..<checkSumArray.count{
interim = self.tableToUse[interim,checkSumArray[i]]
}
return interim
}
}
As you can see, I've had to resort to a really nasty way of dealing with this. It works, but it's very limited, inefficient, and just ugly to look at or maintain. I've looked at the option of using Characters instead of Ints in the Damm Table I've constructed and altering the get/set method to deal with those instead, but that's a lot of extra work and could introduce other issues. Any suggestions of alternative ways to handle this, or a way to convert Characters to Ints would be appreciated.
Thanks!
Based on How convert a *positive* number into an array of digits in Swift, you could do (the number has to be positive):
let checkSumArray = map(number.description) { String($0).toInt()! }
if let int = Int(String(Character("1"))) {
print(int)
}
You can also create a character extension as follow:
extension Character {
var integerValue: Int? {
return Int(String(self))
}
}
Testing
Character("1").integerValue // 1
Character("2").integerValue // 2
Character("3").integerValue // 3
Character("4").integerValue // 4
Character("5").integerValue // 5
Character("6").integerValue // 6
Character("7").integerValue // 7
Character("8").integerValue // 8
Character("9").integerValue // 9
Character("0").integerValue // 0
Character("a").integerValue // nil
Array("9876").first!.integerValue // 9
Array("9876")[1].integerValue // 8
Array("9876")[2].integerValue // 7
Array("9876").last!.integerValue // 6
edit/update Swift 5
Swift 5 adds many new properties to the Character and one of them fits exactly to this purpose. It is called wholeNumberValue
Character("1").wholeNumberValue // 1
Character("2").wholeNumberValue // 2
Character("3").wholeNumberValue // 3
Character("4").wholeNumberValue // 4
Character("④").wholeNumberValue // 4
Character("5").wholeNumberValue // 5
Character("6").wholeNumberValue // 6
Character("7").wholeNumberValue // 7
Character("8").wholeNumberValue // 8
Character("9").wholeNumberValue // 9
Character("0").wholeNumberValue // 0
Character("万").wholeNumberValue // 10_000
Character("a").wholeNumberValue // nil
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()

Resources