How to remove all array items except at indexes at multiples of x - Swift - swift

I have an array of coordinates (965 in total). I want to use these coordinates in Google Roads API however the limit is 100.
I have a function that determines how many items in the array and then gets the value to use.
round(Double(userCoordinatesHardCoded.count / 100))
produces 9.
I would like to remove ALL items that are not at indexes that are multiples of, in this case, 9. So in theory I will only ever have no more than 100 items in the array.
If possible, I would like to keep the first and last array item.

I know this has already been answered, but this is a great use case for using the filter function built into Swift:
let newCoordinates = oldCoordinates.filter { coord in
return (coord % 9 != 0)
}

If space is not a problem, you can create another array with the desired multiples.
var oldCoordinates // Imagine it having all those elements
var newCoordinates : GoogleCoordinates = [] // This one will have new ones
newCoordinates.append(oldCoordinates[0])
var x = 1
for (x; x < oldCoordinates.count ; x++ ) {
if (x % 5 == 0) {
newCoordinates.append(oldCoordinates[x])
}
}
if (x != (oldCoordinates.count - 1)) {
newCoordinates.append(oldCoordinates[oldCoordinates.count - 1])
}

Related

Logic behind Two Number Sum Algorithm

Could someone explain to me the logic behind this hashMap algorithm? I'm getting confused about how the algorithm receives the total sum. I'm starting to learn about algorithms, so it's a little confusing for me. I made comments in my code to pinpoint each line code, but I'm not sure I'm grasping logic correctly. I'm just looking for an easier way to understand how the algorithm works to avoid confusing myself.
//**calculate Two Number Sum
func twoNumberSum(_ array: [Int], _ targetSum: Int) -> [Int] {
//1) initilize our Array to hold Integer Value: Boolean value to store value into hashTable
var numbersHashMap = [Int:Bool]()
//2) create placeHolder called number that iterates through our Array.
for number in array {
//3) variable = y - x
let match = targetSum - number
//4) ??
if let exists = numbersHashMap[match], exists {
//5) match = y / number = x
return [match, number] //
} else {
//6) Store number in HashTable and repeats
numbersHashMap[number] = true
}
}
return []
}
twoNumberSum([3,5,-4, 8, 11, 1, -1, -6], 10)
// x = Number
// y = Unknown *Solve for Y*
Sure, I can walk you through it. So we have a list of numbers, are we are trying to find two numbers that add together to make the specified target. To do this, for each number x, we check if (target - x) is in the list. If it is not, then we add x to the list. If it is, then we return x and (target - x).
Step 4 in your code is the part where we check if (target - x) is in the list. To see why this makes sense, let's walk through an example.
Say we have [2, 3, -1] and our target is 1. In this case, we first consider x = 2 and check our hashmap for (target - x) = (1 - 2) = -1. Since -1 is not in the hashmap, we add 2 to the hashmap. We then consider x = 3 and check for (1 - 3) = -2. Again, -2 is not in the hashmap, so we add it. Now we check x - -1. In this case, when we check (target - x) = (1 - (-1)) = 2, 2 is in the hashmap. Intuitively, we have already "seen" 2, and know that 2 and -1 can be added to get our value.
This is what provides the speed optimization over checking every two numbers in the list.

Better way to find sums in a grid in Swift

I have an app with a 6x7 grid that lets the user input values. After each value is obtained the app checks to find if any of the consecutive values create a sum of ten and executes further code (which I have working well for the 4 test cases I've written). So far I've been writing if statements similar to the below:
func findTens() {
if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue + rowOneColumnFourPlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue + rowOneColumnFourPlaceHolderValue + rowOneColumnFivePlaceHolderValue) == 10 {
//code to execute
}
That's not quite halfway through row one, and it will end up being a very large set of if statements (231 if I'm calculating correctly, since a single 7 column row would be 1,2-1,2,3-...-2,3-2,3,4-...-67 so 21 possibilities per row). I think there must be a more concise way of doing it but I've struggled to find something better.
I've thought about using an array of each of the rowXColumnYPlaceHolderValue variables similar to the below:
let rowOnePlaceHolderArray = [rowOneColumnOnePlaceHolderValue, rowOneColumnTwoPlaceHolderValue, rowOneColumnThreePlaceHolderValue, rowOneColumnFourPlaceHolderValue, rowOneColumnFivePlaceHolderValue, rowOneColumnSixPlaceHolderValue, rowOneColumnSevenPlaceHolderValue]
for row in rowOnePlaceHolderArray {
//compare each element of the array here, 126 comparisons
}
But I'm struggling to find a next step to that approach, in addition to the fact that those array elements then apparently because copies and not references to the original array anymore...
I've been lucky enough to find some fairly clever solutions to some of the other issues I've come across for the app, but this one has given me trouble for about a week now so I wanted to ask for help to see what ideas I might be missing. It's possible that there will not be another approach that is significantly better than the 231 if statement approach, which will be ok. Thank you in advance!
Here's an idea (off the top of my head; I have not bothered to optimize). I'll assume that your goal is:
Given an array of Int, find the first consecutive elements that sum to a given Int total.
Your use of "10" as a target total is just a special case of that.
So I'll look for consecutive elements that sum to a given total, and if I find them, I'll return their range within the original array. If I don't find any, I'll return nil.
Here we go:
extension Array where Element == Int {
func rangeOfSum(_ sum: Int) -> Range<Int>? {
newstart:
for start in 0..<count-1 {
let slice = dropFirst(start)
for n in 2...slice.count {
let total = slice.prefix(n).reduce(0,+)
if total == sum {
return start..<(start+n)
}
if total > sum {
continue newstart
}
if n == slice.count && total < sum {
return nil
}
}
}
return nil
}
}
Examples:
[1, 8, 6, 2, 8, 4].rangeOfSum(10) // 3..<5, i.e. 2,8
[1, 8, 1, 2, 8, 4].rangeOfSum(10) // 0..<3, i.e. 1,8,1
[1, 8, 3, 2, 9, 4].rangeOfSum(10) // nil
Okay, so now that we've got that, extracting each possible row or column from the grid (or whatever the purpose of the game is) is left as an exercise for the reader. 🙂

Loop through a range of an Array [duplicate]

This question already has answers here:
How to loop through an array from the second element in elegant way using Swift
(5 answers)
Closed 3 years ago.
How can I loop through an array range? Example if I had 5 objects in an array. I want to loop from index [3] to end of the array in this example it would go through and update objects 3-5 and skip objects 1 & 2. This is what I have so far using the stride method(this code isn't working). Is this the correct method? How can I achieve this?
stride(from: markers[index], to: markers.endIndex, by: 1).forEach { i in
// Do something for each array object
}
You can use the range operator to get sequences of indices or slices of the array. Which you use depends on what you are trying to do. For clarity I am going to leave out error checking.
For example:
let letters = ["a", "b", "c", "d", "e"]
letters[3...].forEach { print($0) } // prints d e
// or you can print up to index 3
letters[...3].forEach { print($0) } // prints a b c d
// or print elements 1-3 inclusive
letters[1...3].forEach { print($0) } // prints b c d
// or print elements 1-3 excluding index 3
letters[1..<3].forEach { print($0) } // prints b c d
If you wanted to modify the elements of the array you pass in the indices rather than the elements
var mutableLetters = ["a","b","c","d","e"]
(3..<mutableLetters.count).forEach {
mutableLetters[$0] = mutableLetters[$0].uppercased()
}
notice here we need to specify both limits because the range knows nothing about the array.
It's often more Swifty not to modify things in place so, if this fits your use case you might consider something like this:
let immutableLetters = ["a","b","c","d","e"]
let upperCasedFromThreeOn = immutableLetters[3...].map { $0.uppercased() }
// upperCasedFromThreeOn = ["D","E"]
As a final note, sometimes you need to know both the index and the element. You can use a forEach on the indices as above, but another way is to use enumerated() this creates a tuple of the index and element.
let range = 2...4
immutableLetters.enumerated()
.filter { (index,_) in range.contains(index) }
.forEach { (index, element) in
print("\(index) \(element)")
}
Here I've used a filter after the enumeration so that the indices match the original array.
You can simply iterate over your array slice dropping the first n elements:
let markers = ["a","b","c","d","e"]
for marker in markers.dropFirst(2) {
print(marker) // this will print 'c d e'
}
If you need to change your array you can iterate over a slice of its indices:
let markers = ["a","b","c","d","e"]
for index in markers.indices.dropFirst(2) {
print(markers[index])
}
You can simply loop through the array using Range Operator in Swift like,
var markers = ["M1","M2","M3","M4","M5"]
let count = markers.count
if count > 2 {
for i in 2..<count {
//add your code here..
}
}
In the above code, I've used half-open range operator(..<)

How can I search through this array for a specific value then return the other value in the tuple?

I have a large array of (x,y) pairs:
P =
[
(0.0, 500000.09999999998),
(0.001, 18.332777589999999),
(0.002, 18.332221480000001),
(0.0030000000000000001, 18.331665000000001),
(0.0040000000000000001, 18.331108140000001),
(0.0050000000000000001, 18.33055092),
(0.0060000000000000001, 18.32999332),
...
]
I now need to use this in my code. I need to search for a specific x-value and, if the x-value exists, return its corresponding y-value.
Note: If there is a better format I could put my (x,y) pairs in, please feel free to let me know. For example, 2 separate arrays where one holds the x-values and the other holds the y-values. Then I could use the index to find the corresponding y-value or something.
Edit:
A user made a very good point in the comments: how can I reliably compare x == 0.001?
The way I will be using my code is this: I am evaluating a function f(x) at values of x. However, if at a particular value of x there is a y value in the P array, then I need to do an extra subtraction calculation (the details of which are not too important here). The problem, then, is that what if I pass the x value 0.001 in there and the P array does not have a correpsonding y value, but it does have one for 0.001000000009?? Then the code will say there is no value, but in reality it is reasonably close to the intended x value.
I'd suggest to let your array to be an array of CGPoints. It's simply:
A structure that contains a point in a two-dimensional coordinate
system.
However, if you want to get the y values based on searching the x:
let myArray = [
(0.0, 500000.09999999998),
(0.001, 18.332777589999999),
(0.002, 18.332221480000001),
(0.0030000000000000001, 18.331665000000001),
(0.0040000000000000001, 18.331108140000001),
(0.0050000000000000001, 18.33055092),
(0.0060000000000000001, 18.32999332),
]
// this array should contains y values for a given x value
// for example, I search the x value of 0.0
let yValues = myArray.filter { $0.0 == 0.0 }.map { $0.1 }
print(yValues) // [500000.09999999998]
Hope this helped.
A good way of doing this is by declaring this function:
func getValueFromTuples(tupleArr:[(Double,Double)],n:Double)->Double?{
for tuple in tupleArr{
if tuple.0 == n{
return tuple.1
}
}
return nil
}
Then, you can use it like this:
var tupleArray: [(Double,Double)] = [(1.0, 12.0),(2.0,23.0),(3.0,34.0),(4.0,45.0),(5.0,56.0)]
var x:Double = 1.0
print(getValueFromTuples(tupleArr: tupleArray,n:x) ?? "No value found") // 12.0
Where the n argument is the value to be found, the tuple is the key-value pair formed by the numbers and getValueFromTuples returns the value y if x has been found, else nil.
This returns "No value found" if the value does not exist in the array of tuples.
Hope this helps!
Your x value all seem to increase by 0.001. If that is the case, you could also calculate the index and return the y value at this index. This would be a lot more efficient.
func calculateIndex(forX x: Double) -> Int {
let increase = 0.001
return Int(x/0.001)
}
You can use the find method to find the index of the x value and then return the y value. I would multiply your values by 1000 and then compare the Int instead of comparing Double.
func findYValue(forX x: Double) -> Double? {
let multiply = 1000
let x = Int(multiply*x)
if let index = array.index(where: { Int($0.0 * multiply) == x }) {
return array[index].1 //found the y value
}
return nil //x is not in the array
}
Instead of using tuples, I would personally use CGPoint. The class has an x and a y property, which makes your code more readable.
Microsoft gives a very thorough explanation of how to compare 2 doubles. The basic premise is that you need to define a certain level of tolerance. The article the explores how to pick a good tolerance in most cases.
Here's code translated to Swift:
func areEqual(_ lhs: Double, _ rhs: Double, units: Int = 3) -> Bool {
let lValue = Int64(bitPattern: lhs.bitPattern)
let rValue = Int64(bitPattern: rhs.bitPattern)
let delta = lValue - rValue
return abs(delta) <= Int64(units)
}
Test:
var n = 0.0
for _ in 0..<10 {
n += 0.1
}
// n should equal 1 but it does not
print(n == 1.0) // false
print(areEqual(1.0, n)) // true
Back to your problem, it becomes straight forward after you defined how to test for equality in 2 doubless:
let x = 0.003
if let y = p.first(where: { areEqual($0.0, x) })?.1 {
print(y)
}

How do you assign a slice of numbers to an array in swift

x is an object that holds an array called point.
x implements the subscript operator so you can do things, like x[i] to get the array's ith element (of type T, which is usually an Int or Double).
This is what I want to do:
x[0...2] = [0...2]
But I get an error that says ClosedInterval<T> is not convertible to Int/Double.
Edit1:
Here is my object x:
let x = Point<Double>(dimensions:3)
For kicks and giggles: define x as [1.0,2.0,0.0]
I can get the first n elements via x[0...2].
What I want to know is how to update x[0...2] to hold [0.0, 0.0.0.0] in one fell swoop. Intuitively, I would want to do x[0...2] = [0...2]. This does not work as can be seen in the answers. I want to update x without iteration (on my end) and by hiding the fact that x is not an array (even though it is not).
[0...2] is an array with one element which, at best, will be a Range<Int> from 0 through 2. You can't assign that to a slice containing, say, Ints.
x[0...2] on the other hand is (probably) a slice, and Sliceable only defines a get subscript, not a setter. So even if the types were more compatible - that is, if you tried x[0...2] = 0...2, which at least is attempting to replace a range within x with the values of a similarly-sized collection - it still wouldn't work.
edit: as #rintaro points out, Array does support a setter subscript for ranges – so if x were a range you could do x[0...2] = Slice(0...2) – but it has to be a slice you assign, so I'd still go with replaceRange.
If what you mean is you want to replace entries 0 through 2 with some values, what you want is replaceRange, as long as your collection conforms to RangeReplaceableCollection (which, for example, Array does):
var x = [0,1,2,3,4,5]
var y = [200,300,400]
x.replaceRange(2..<5, with: y)
// x is now [0,1,200,300,400,5]
Note, the replaced range and y don't have to be the same size, the collection will expand/contract as necessary.
Also, y doesn't have to an array, it can be any kind of collection (has to be a collection though, not a sequence). So the above code could have been written as:
var x = [0,1,2,3,4,5]
var y = lazy(2...4).map { $0 * 100 }
x.replaceRange(2..<5, with: y)
edit: so, per your edit, to in-place zero out an array of any size in one go, you can do:
var x = [1.0,2.0,0.0]
// range to replace is the whole array's range,
// Repeat just generates any given value n times
x.replaceRange(indices(x), with: Repeat(count: x.count, repeatedValue: 0.0))
Adjust the range (and count of replacing entries) accordingly if you want to just zero out a subrange.
Given your example Point class, here is how you could implement this behavior assuming it's backed by an array under the hood:
struct Point<T: FloatLiteralConvertible> {
private var _vals: [T]
init(dimensions: Int) {
_vals = Array(count: dimensions, repeatedValue: 0.0)
}
mutating func replaceRange
<C : CollectionType where C.Generator.Element == T>
(subRange: Range<Array<T>.Index>, with newElements: C) {
// just forwarding on the request - you could perhaps
// do some additional validation first to ensure dimensions
// aren't being altered...
_vals.replaceRange(subRange, with: newElements)
}
}
var x = Point<Double>(dimensions:3)
x.replaceRange(0...2, with: [1.1,2.2,3.3])
You need to implement subscript(InvervalType) to handle the case of multiple assignments like this. That isn't done for you automatically.