Access in array in specific indices - ios

I am trying to access an array in a function, as far as I understand there is no Arraylists in Swift, so I am trying to use regular list:
func findNearsetPoints(pointsArray: [Point] , myPoint: Point )-> Array <Point>{
var twoPoint = [Point]()
var minDist1:Double = DBL_MAX;
var minDist2:Double = DBL_MAX;
var distance:Double = 0
for element in pointsArray{
distance = getDistanceBetweenTwoPoints(pointsArray[element], Point); //error 0
if (distance < minDist1) {
minDist1 = distance;
twoPoint[1] = twoPoint[0];
twoPoint[0] = pointsArray[element]; // error 1
}
else if (distance < minDist2) {
minDist2 = distance;
twoPoint[1] = pointsArray[element]; //error 1
}
}
return twoPoint;
}
func getDistanceBetweenTwoPoints(point1:Point , point2:Point )->Double{
return 5; //TODO
}
error 0:
/Users/user/Desktop/proj/ViewController.swift:145:38: Cannot subscript a value of type '[ViewController.Point]' with an index of type 'ViewController.Point'
error 1:
/Users/user/Desktop/proj/ViewController.swift:149:38: Cannot subscript a value of type '[ViewController.Point]' with an index of type 'ViewController.Point'
What is wrong with the code?
thanks!

your element is already a Point and not an index.
for element in pointsArray{
distance = getDistanceBetweenTwoPoints(point1: element, point2: myPoint) // fix here
if (distance < minDist1) {
minDist1 = distance;
twoPoint[1] = twoPoint[0];
twoPoint[0] = element; // fix here
}
else if (distance < minDist2) {
minDist2 = distance;
twoPoint[1] = element; // fix here
}
}
PS:
take a loook also to this question "Sort array by calculated distance in Swift" for better calculation of distance. just sort the array by distance and then take the first from the array after it is sorted. thats more easy to do

You declared getDistanceBetweenTwoPoints as taking named parameters.
With the current declaration, you need to call it using this syntax:
getDistanceBetweenTwoPoints(point1: aPoint, point2: anotherPoint)
If you want to call it without labels on the parameters then you should redefine it like this:
func getDistanceBetweenTwoPoints(
_ point1:Point ,
_ point2:Point )->Double{
return 5; //TODO
}

Related

Get closest value in array to variable value

I have an array of int I'd like to create a function which retrieves from this array the closest value to randomInt
final myArray = [10 , 20, 14, 15, 18, 24];
final int randomInt = 21;
getClosestValueInArray(myArray, randomInt); // should return 20
int getClosestValueInArray(List<int> array, int value) {
}
You could loop through the array and check closeness for each element. E.g. in pseudo-code:
closest = myArray[0]
best_closeness = abs(myArray[0] - randomInt)
for (element in myArray) {
closeness = abs(element - randomInt)
if (closeness < best_closeness) {
closest = element
best_closeness = closeness
}
}
return closest
And in Dart (added by #julemand101)
int getClosestValueInArray(List<int> array, int value) {
int closest = array.first;
int best_closeness = (closest - value).abs();
for (int element in array.skip(1)) {
int closeness = (element - value).abs();
if (closeness < best_closeness) {
closest = element;
best_closeness = closeness;
}
}
return closest;
}
One option is to put these elements in a TreeSet and then use ts.floor(randomInt) and ts.ceil(randomInt) to check what the nearest elements to randomInt is, and pick the one with the smallest absolute difference to randomInt.
Another option is to put these values in a hashset and then search for randomInt - 1, randomInt + 1, randomInt - 2 and so on. This again has benefits and drawbacks compared to the previous approach.
There are many other ways.

Integers Larger than Int64

I'm attempting to get a user input number and find the sum of all the digits. I'm having issues with larger numbers, however, as they won't register under an Int64. Any idea as to what structures I could use to store the value? (I tried UInt64 and that didn't work very well with negatives, however, I'd prefer something larger than UInt64, anyways. I'm having a hard time implementing a UInt128 from Is there a number type with bigger capacity than u_long/UInt64 in Swift?)
import Foundation
func getInteger() -> Int64 {
var value:Int64 = 0
while true {
//we aren't doing anything with input, so we make it a constant
let input = readLine()
//ensure its not nil
if let unwrappedInput = input {
if let unwrappedInt = Int64(unwrappedInput) {
value = unwrappedInt
break
}
}
else { print("You entered a nil. Try again:") }
}
return value
}
print("Please enter an integer")
// Gets user input
var input = getInteger()
var arr = [Int] ()
var sum = 0
var negative = false
// If input is less than 0, makes it positive
if input < 0 {
input = (input * -1)
negative = true
}
if (input < 10) && (input >= 1) && (negative == true) {
var remain = (-1)*(input%10)
arr.append(Int(remain))
input = (input/10)
}
else {
var remain = (input%10)
arr.append(Int(remain))
input = (input/10)
}
}
// Adds numbers in array to find sum of digits
var i:Int = 0
var size:Int = (arr.count - 1)
while i<=size {
sum = sum + arr[i]
i = (i+1)
}
// Prints sum
print("\(sum)")
You can use a string to perform the operation you describe. Loop through each character and convert it to an integer and add to the sum. Be careful to handle errors.

Best way to check if object is out of bounds in array

What is the best practice to check if an object exists (is within bounds) at a specific index in an Array?
It would be nice to have it as simple as this, but that is unfortunately not possible:
let testArray = ["A", "B", "C", "D"]
if let result = testArray[6] {
println("Result: \(result)")
}
else {
println("Result does not exist. Out of bounds.")
}
Will I have to check against the total count?
Thank you!
You could also make an extension to Array, so you will be able to check with if-let:
extension Array {
func at(index: Int) -> Element? {
if index < 0 || index > self.count - 1 {
return nil
}
return self[index]
}
}
let arr = [1, 2, 3]
if let value = arr.at(index: 2) {
print(value)
}
You can use the ~= operator in conjunction with the indices function, which is a shortcut for creating a range of the full index range of a container:
let a = [1,2,3]
let idx = 3 // one past the end
if indices(a) ~= idx {
println("within")
}
else {
println("without")
}
The one thing to note is this works with any kind of container that has a comparable index, not just ones like array that have integer indices. Thinking of indices as numbers is generally a good habit to get out of, since it helps you think more generally about algorithms on containers without these indices, such as strings or dictionaries:
let s = "abc"
let idx = s.endIndex
idx < count(s) // this won't compile
idx < s.startIndex // but this will
// and so will this
if indices(s) ~= idx {
println("within")
}
else {
println("without")
}
The more general your algorithms, the more chance you will be able to factor them out into generics and increase re-use.
#alkku has it but for simplicity and using the most underused syntactic form in all languages ?::
extension Array {
func atIndex(index: Int) -> T? {
return (0 <= index && index < self.count
? self[index]
: nil)
}
}
There is a new (neat) way to do it in Swift:
array.indices.contains(index)
Check if object index used should be greater or equal to zero and should be less total count of array like this :
//Here index is object you want for
if(index >= 0 && index < [yourArray count])
{
//inside of array
}
else
{
//out of bound
}
To check whether or not an index is inside the bounds of an array in swift you would use
if index < testArray.count {
//index is inside bounds
} else {
//index is outside bounds
}

Random number from an array without repeating the same number twice in a row?

I am making a game using Swift and SpriteKit where i move an object to random locations based on an array.
The array that is made up of CGPoints:
let easyArray = [CGPointMake(0,0), CGPointMake(126.6,0), CGPointMake(253.4,0), CGPointMake(0,197.5), CGPointMake(126.7,197.5), CGPointMake(253.4,197.5), CGPointMake(0,395), CGPointMake(126.7,395), CGPointMake(253.4,395)]
I use this function to generate a random number:
func randomNumber(maximum: UInt32) -> Int {
var randomNumber = arc4random_uniform(maximum)
while previousNumber == randomNumber {
randomNumber = arc4random_uniform(maximum)
}
previousNumber = randomNumber
return Int(randomNumber)
}
I used this to move the object based on the random number generated:
let greenEasy = randomNumberNew(9)
let moveSelector = SKAction.moveTo(easyArray[greenEasy], duration: 0)
selector.runAction(moveSelector)
I have done some reading online and found that the "While" condition should make it so that the same random number isn't generate twice in a row. But it still happens.
Can anyone please help me on how to make it so i don't get the same number twice in a row?
The code below doesn't random the same number.
var currentNo: UInt32 = 0
func randomNumber(maximum: UInt32) -> Int {
var randomNumber: UInt32
do {
randomNumber = (arc4random_uniform(maximum))
}while currentNo == randomNumber
currentNo = randomNumber
return Int(randomNumber)
}
I think Larme's suggestion is pretty clever, actually.
easyArray.append(easyArray.removeAtIndex(Int(arc4random_uniform(UInt32(easyArray.count)-1))))
selector.runAction(SKAction.moveTo(easyArray.last!, duration: 0))
I would recommend to not use while() loops with randomizers.
Theoretically it can cause infinite loops in worst case scenario, in more positive scenario it will just take few loops before you get desired results.
Instead I would advice to make an NSArray of all values, remove from this NSArray last randomized element and randomize any of other existing elements from such an array - that is guarantee result after only one randomize iteration.
It can be easily achieved by making NSArray category in Objective-C:
- (id) randomARC4Element
{
if(self.count > 0)
{
return [self objectAtIndex:[self randomIntBetweenMin:0 andMax:self.count-1]];
}
return nil;
}
- (int)randomIntBetweenMin:(int)minValue andMax:(int)maxValue
{
return (int)(minValue + [self randomFloat] * (maxValue - minValue));
}
- (float)randomFloat
{
return (float) arc4random() / UINT_MAX;
}
If you can use linq then you can select a random value that doesn't match the last value. Then for any left over values you can loop through and find valid places to insert them.
It's not the most efficient but it works.
public static List<int> Randomize(List<int> reps, int lastId) {
var rand = new Random();
var newReps = new List<int>();
var tempReps = new List<int>();
tempReps.AddRange(reps);
while (tempReps.Any(x => x != lastId)) {
var validReps = tempReps.FindAll(x => x != lastId);
var i = rand.Next(0, validReps.Count - 1);
newReps.Add(validReps[i]);
lastId = validReps[i];
tempReps.Remove(validReps[i]);
}
while (tempReps.Any()) {
var tempRep = tempReps.First();
bool placed = false;
for (int i = 0; i < newReps.Count; i++) {
if (newReps[i] == tempRep) {
continue;
}
else if ((i < newReps.Count - 1) && (newReps[i + 1] == tempRep)) {
continue;
}
else {
newReps.Insert(i + 1, tempRep);
placed = true;
break;
}
}
if (placed) {
tempReps.Remove(tempRep);
}
else {
throw new Exception("Unable to randomize reps");
}
}
return newReps;
}

Immutable array on a var?

I am getting the error:
Immutable value of type 'Array Character>' only has mutating members of name removeAtIndex()
The array should have contents because that removeAtIndex line is in a loop who's condition is if the count > 1
func evaluatePostFix(expression:Array<Character>) -> Character
{
var stack:Array<Character> = []
var count = -1 // Start at -1 to make up for 0 indexing
if expression.count == 0 {
return "X"
}
while expression.count > 1 {
if expression.count == 1 {
let answer = expression[0]
return answer
}
var expressionTokenAsString:String = String(expression[0])
if let number = expressionTokenAsString.toInt() {
stack.append(expression[0])
expression.removeAtIndex(0)
count++
} else { // Capture token, remove lefthand and righthand, solve, push result
var token = expression(count + 1)
var rightHand = stack(count)
var leftHand = stack(count - 1)
stack.removeAtIndex(count)
stack.removeAtIndex(count - 1)
stack.append(evaluateSubExpression(leftHand, rightHand, token))
}
}
}
Anyone have any idea as to why this is? Thanks!
Because all function parameters are implicitly passed by value as "let", and hence are constant within the function, no matter what they were outside the function.
To modify the value within the function (which won't affect the value on return), you can explicitly use var:
func evaluatePostFix(var expression:Array<Character>) -> Character {
...
}

Resources