How to copy end of the Array in swift? - swift

There must be some really elegant way of copying end of the Array using Swift starting from some index, but I just could not find it, so I ended with this:
func getEndOfArray<T>( arr : [T], fromIndex : Int? = 0) -> [T] {
var i=0;
var newArray : [T] = [T]()
for item in arr {
if i >= fromIndex {
newArray.append(item)
}
i = i + 1;
}
return newArray // returns copy of the array starting from index fromIndex
}
Is there a better way of doing this without extra function?

And another one ...
let array = [1, 2, 3, 4, 5]
let fromIndex = 2
let endOfArray = array.dropFirst(fromIndex)
print(endOfArray) // [3, 4, 5]
This gives an ArraySlice which should be good enough for most
purposes. If you need a real Array, use
let endOfArray = Array(array.dropFirst(fromIndex))
An empty array/slice is created if the start index is larger than (or equal to) the element count.

You can use suffix:
let array = [1,2,3,4,5,6]
let lastTwo = array.suffix(2) // [5, 6]
As mentioned in the comment: This gives you an ArraySlice object which is sufficient for most cases. If you really need an Array object you have to cast it:
let lastTwoArray = Array(lastTwo)

You can subscript an open ended range now. This will include elements starting at index 5.
Swift 4.2
array[5...]

This is one possible solution, there are probably a few more
let array = [1, 2, 3, 4, 5]
let endOfArray = Array(array[2..<array.endIndex]) // [3, 4, 5]
Or with dynamic index and range check
let array = [1, 2, 3, 4, 5]
let index = 2
let endOfArray : [Int]
if index < array.count {
endOfArray = Array(array[index..<array.endIndex]) // [3, 4, 5]
} else {
endOfArray = array
}
The re-initializition of the array is needed since the range subscription of Array returns ArraySlice<Element>

You could use the new method removeFirst(_:) in Swift 4
var array = [1, 2, 3, 4, 5]
array.removeFirst(2)
print(array) // [3, 4, 5]

You could use filter
func getEndOfArray( arr : [Int], fromIndex : Int? = 0) -> [Int] {
let filteredArray = arr.filter({$0 <= fromIndex})
return filteredArray
}
took the liberty of changing to [Int] for the sake of this example.

Related

Convert string elements to int elements in an array in swift

I have a string with the following format:
var cadenaCoordenadas = """
1,1
1,3
4,1
5,1
1,5
1,6
2,5
0,0
"""
What I want is that each line is in the following format (in an array) to manipulate it (with Int data types as I will do operations with the new string):
[1,1]
I have the following code:
var arregloEntradas = cadenaCoordenadas.split(separator: "\n")
print("primer Arreglo: ", arregloEntradas)
for i in stride(from: 0, through:arregloEntradas.count - 1, by: 1){
let arregloEntradasFinal = arregloEntradas[i].split(separator: ",")
print(arregloEntradasFinal)
}
and I get the result of this:
this is the result
as you can see, the array elements are of string type, however I require them to be of Int type:
[1,1]
[1,3]
[4,1]
...
I hope you can help me, thank you in advance.
Here's one approach using some splitting and mapping:
var cadenaCoordenadas = """
1,1
1,3
4,1
5,1
1,5
1,6
2,5
0,0
"""
let arregloEntradasFinal = cadenaCoordenadas.split(separator: "\n")
.map { $0.split(separator: ",").compactMap { Int($0) } }
print(arregloEntradasFinal)
Output:
[[1, 1], [1, 3], [4, 1], [5, 1], [1, 5], [1, 6], [2, 5], [0, 0]]
var arregloEntradas = cadenaCoordenadas.split(separator: "\n")
print("primer Arreglo: ", arregloEntradas)
for i in stride(from: 0, through:arregloEntradas.count - 1, by: 1){
let arregloEntradasFinal = arregloEntradas[i].split(separator: ",").map { Int(String($0)) }
print(arregloEntradasFinal)
}
What you're getting in arregloEntradasFinal is correct since you're processing the string array. Later, when you want to use arregloEntradasFinal again, you should again split a string by a comma separator from arregloEntradasFinal and use the individual Int value. For example:
let index = 0 // You can also loop through the array
let values = arregloEntradasFinal[index].split(separator: ",")
let num1 = Int(values.first ?? 0) // If no value then returns 0
let num2 = Int(values.last ?? 0) // If no value then returns 0
Note - this is one of the way without using the map function.

Find closest longest combination

I have an array with integers [1, 2, 3, 7, 13, 11, 4] and an integer value 12. I need to return an array of a closest combination of sum of the integer values in the new array.
For example: [1, 2, 3, 7, 13, 11, 4] with value 12. The array that need to returned is [1, 2, 3, 4] because the sum of elements 1 + 2 + 3 + 4 <= 12. This is the longest array and prefered over [1, 7, 4] 1 + 7 + 4 = 12.
this solution works if you dont have repeated numbers in array.
var array = [1, 2, 3, 7, 13, 11, 4, -12, 22, 100]
print(array.sorted())
let value = 19
func close(array: [Int], value: Int) -> (Int , Int) {
let sortedArray = array.sorted()
var lastNumberBeforValue = sortedArray.first!
for (index,number) in sortedArray.enumerated() {
let sub = value - number
if sub > 0 {
lastNumberBeforValue = number
}
if sortedArray.contains(sub) && sub != number {
return (sub, number)
} else if index == sortedArray.count - 1 {
if sub < 0 {
let near = close(array: array, value: value - lastNumberBeforValue)
return (near.0, lastNumberBeforValue)
}
let near = close(array: array, value: sub)
return (near.0, number)
}
}
return (-1,-1)
}
let numbers = close(array: array, value: value)
print(numbers) //prints (4, 13)
This solution also finds the two Integers in an array which sum is closest to a given value:
let array = [1, 2, 3, 7, 13, 11, 4]
let value = 5
var difference = Int.max
var result = [Int(), Int()]
for firstInt in array {
for secondInt in array {
let tempDifference = abs((firstInt + secondInt) - value)
if tempDifference < difference {
difference = tempDifference
result[0] = firstInt
result[1] = secondInt
}
}
}
Or a solution that doesn't allow multiple use of the same value:
for (firstIndex, firstInt) in array.enumerated() {
for (secondIndex, secondInt) in array.enumerated() {
guard firstInt != secondInt else { break }
let tempDifference = abs((firstInt + secondInt) - value)
if tempDifference < difference {
difference = tempDifference
result[0] = firstInt
result[1] = secondInt
}
}
}
You can keep on nesting for-loops and guarding for multiple use of same index, if you want longer result arrays. Finally you can take the valid array with the largest result.count. This is not a vary nice solution though, since it computationally heavy, and requires the array to have a static length.
I'm not necessary good with algorithms but I would do it like that :
Since your rule is <= 5 you can sort your array : [1, 2, 3, 7, 13, 11, 4] => [1, 2, 3, 4, 7, 11, 13]
Then, as you don't need integer > 5 you can split your array in 2 parts and take only the first one : [1, 2, 3, 4]
From there you have to add 4 + 3 and match with your value. If it doesn't work do 4 + 2, then 4 + 1. If it's still > 5, loop with 3,2 ; 3,1 ; etc. I did something like this in a Swift way :
// Init
let array = [1, 2, 3, 7, 13, 11, 4]
let value = 5
let sortedArray = array.sorted()
let usefulArray = sortedArray.filter() {$0 < value}
var hasCombination = false
var currentIndex = usefulArray.count - 1
var indexForSum = currentIndex - 1
// Process
if currentIndex > 0 {
hasCombination = true
while usefulArray[currentIndex] + usefulArray[indexForSum] > value {
indexForSum -= 1
if indexForSum < 0 {
currentIndex -= 1
indexForSum = currentIndex - 1
}
if currentIndex == 0 {
hasCombination = false
break
}
}
}
// Result
if hasCombination {
let combination = [usefulArray[indexForSum], usefulArray[currentIndex]]
} else {
print("No combination")
}
I guess it works, tell me if it doesn't !

Simple Swift Fibonacci program crashing (Project Euler 2)

I am trying to solve the second problem on Project Euler. The problem is as follows:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
I think I've written a solution, but when I try to run my code it crashes my Swift playground and gives me this error message:
Playground execution aborted: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
var prev = 0
var next = 1
var num = 0
var sum = 0
for var i = 1; i < 400; i++ {
num = prev + next
if next % 2 == 0 {
sum += next
}
prev = next
next = num
}
print(sum)
The weird thing is, if I set the counter on my loop to less than 93, it works fine. Explicitly setting the variable names to Double does not help. Anyone know what's going on here?
There is nothing weird about this at all. Do you know how large the 400 fibonacci number is?
176023680645013966468226945392411250770384383304492191886725992896575345044216019675
Swift Int64 or UInt64 simply cannot handle that large of a number. The later can go up to 18446744073709551615 at max - not even close.
If you change your variables to be doubles it works but will be inaccurate:
var prev : Double = 0
var next : Double = 1
var num : Double = 0
var sum : Double = 0
will yield
2.84812298108489e+83
which is kind of close to the actual value of
1.76e+83
Luckily you do not need to get values that big. I would recommend not writing a for loop but a while loop that calculates the next fibonacci number until the break condition is met whose values do not exceed four million.
The Fibonacci numbers become very large quickly. To compute large Fibonacci numbers, you need to implement some kind of BigNum. Here is a version the makes a BigNum that is implemented internally as an array of digits. For example, 12345 is implemented internally as [1, 2, 3, 4, 5]. This makes it easy to represent arbitrarily large numbers.
Addition is implemented by making the two arrays the same size, then map is used to add the elements, finally the carryAll function restores the array to single digits.
For example 12345 + 67:
[1, 2, 3, 4, 5] + [6, 7] // numbers represented as arrays
[1, 2, 3, 4, 5] + [0, 0, 0, 6, 7] // pad the shorter array with 0's
[1, 2, 3, 10, 12] // add the arrays element-wise
[1, 2, 4, 1, 2] // perform carry operation
Here is the implementation of BigNum. It is also CustomStringConvertible which makes it possible to print the result as a String.
struct BigNum: CustomStringConvertible {
var arr = [Int]()
// Return BigNum value as a String so it can be printed
var description: String { return arr.map(String.init).joined() }
init(_ arr: [Int]) {
self.arr = carryAll(arr)
}
// Allow BigNum to be initialized with an `Int`
init(_ i: Int = 0) {
self.init([i])
}
// Perform the carry operation to restore the array to single
// digits
func carryAll(_ arr: [Int]) -> [Int] {
var result = [Int]()
var carry = 0
for val in arr.reversed() {
let total = val + carry
let digit = total % 10
carry = total / 10
result.append(digit)
}
while carry > 0 {
let digit = carry % 10
carry = carry / 10
result.append(digit)
}
return result.reversed()
}
// Enable two BigNums to be added with +
static func +(_ lhs: BigNum, _ rhs: BigNum) -> BigNum {
var arr1 = lhs.arr
var arr2 = rhs.arr
let diff = arr1.count - arr2.count
// Pad the arrays to the same length
if diff < 0 {
arr1 = Array(repeating: 0, count: -diff) + arr1
} else if diff > 0 {
arr2 = Array(repeating: 0, count: diff) + arr2
}
return BigNum(zip(arr1, arr2).map { $0 + $1 })
}
}
// This function is based upon this question:
// https://stackoverflow.com/q/52975875/1630618
func fibonacci(to n: Int) {
guard n >= 2 else { return }
var array = [BigNum(0), BigNum(1)]
for i in 2...n {
array.append(BigNum())
array[i] = array[i - 1] + array[i - 2]
print(array[i])
}
}
fibonacci(to: 400)
Output:
1
2
3
5
8
...
67235063181538321178464953103361505925388677826679492786974790147181418684399715449
108788617463475645289761992289049744844995705477812699099751202749393926359816304226
176023680645013966468226945392411250770384383304492191886725992896575345044216019675

Combining 2 arrays into a dictionary in Xcode 6, swift?, with corresponding index values)

In my app, I have 2 arrays which are in use a lot, an array that stores score values as an Integer, and another array that stores dates in the format "mm/dd/yy". These arrays are continuously being appended, and the indexes of these arrays correspond to each other, for example, index 0 of dates array corresponds to index 0 of score array. I want these arrays to be turned into a dictionary upon when a second screen loads(these are global variables). For example, these are the type of values in each array.
score == [1,2,3,4,5,6,7,8,9]
dates == ["7/12/15","7/12/15","7/12/15","7/12/15","7/13/15","7/13/15","7/13/15","7/13/15"," 7/14/15"]
What I want to happen, is that upon viewDidLoad(), this gets created.
var scoreDatesDictionary = [
"7/12/15": [1,2,3,4]
"7/13/15": [5,6,7,8]
"7/14/15": [9]
]
In its essence, the two arrays have corresponding values, (firstArray[0]) corresponds to (secondArray[0]). I am trying to make it that in the secondArray(dates), identical strings get matched up in a dictionary with their corresponding index values. I may not make much sense, but the sample code I provided should work. I spent a lot of time working with this, and I can't find a solution.
let score = [1,2,3,4,5,6,7,8,9,]
let dates = ["7/12/15","7/12/15","7/12/15","7/12/15","7/13/15","7/13/15","7/13/15","7/13/15"," 7/14/15"]
var dic = [String:[Int]]()
for var index=0;index < dates.count; index++ {
let key = dates[index];
var value = dic[key]
if value == nil{
dic[key] = [score[index]]
}else{
value!.append(score[index])
dic[key] = value
}
}
println(dic)
This will log
[7/12/15: [1, 2, 3, 4], 7/14/15: [9], 7/13/15: [5, 6, 7, 8]]
func zipToDict<
S0 : SequenceType,
S1 : SequenceType where
S0.Generator.Element : Hashable
>(keys: S0, values: S1) -> [S0.Generator.Element:[S1.Generator.Element]] {
var dict: [S0.Generator.Element:[S1.Generator.Element]] = [:]
for (key, value) in zip(keys, values) {
dict[key] = (dict[key] ?? []) + [value]
}
return dict
}
let score = [1,2,3,4,5,6,7,8,9]
let dates = ["7/12/15","7/12/15","7/12/15","7/12/15","7/13/15","7/13/15","7/13/15","7/13/15"," 7/14/15"]
print(zipToDict(dates, score)) // [7/12/15: [1, 2, 3, 4], 7/14/15: [9], 7/13/15: [5, 6, 7, 8]]
Working off #Leo's correct answer, here's a version that makes use of enumerate and the nil coalescing operator ?? to do this more cleanly:
For Swift 1.2:
let score = [1,2,3,4,5,6,7,8,9]
let dates = ["7/12/15","7/12/15","7/12/15","7/12/15","7/13/15","7/13/15","7/13/15","7/13/15"," 7/14/15"]
var dic = [String:[Int]]()
for (index, date) in enumerate(dates) {
dic[date] = (dic[date] ?? []) + [score[index]]
}
print(dic) // prints "[7/12/15: [1, 2, 3, 4], 7/14/15: [9], 7/13/15: [5, 6, 7, 8]]"
For Swift 2.0, you need to use dates.enumerate() instead.

How do I insert an item repeatedly between every two elements of an array?

I have this code:
let items = [1, 2, 3]
let sep = 0
I want to insert sep between every two elements of items to get a result similar to this:
newItems = [1, 0, 2, 0, 3]
Is there a concise way to do this through functional programming in Swift? Something similar to String.join(), but for arrays.
(Note: The answer has been updated for Swift 3 and later with the help of Brandon's answer and ober's answer).
This does the trick:
let items = [1, 2, 3]
let sep = 0
let newItems = Array(items.map { [$0] }.joined(separator: [sep]))
print(newItems) // [1, 0, 2, 0, 3]
items.map { [ $0 ] } creates an array of single-element arrays, and joined(separator: [sep]) then interposes the separator and concatenates
the elements. The result is a JoinedSequence from which we can create an Array.
As it turns out (benchmarks below) it is quite expensive to create many temporary arrays. This can be avoided by using “single-element collections”:
let newItems = Array(items.map(CollectionOfOne.init).joined(separator: CollectionOfOne(sep)))
Another possible solution is
let newItems = (0 ..< 2 * items.count - 1).map { $0 % 2 == 0 ? items[$0/2] : sep }
which maps even indices to the corresponding element of items,
and odd indices to the separator. This turns out to be the fastest solution for large arrays.
Benchmark: With items containing 1,000,000 elements, compiled in Release mode on a 2.3 GHz Intel Core i7 MacBook Pro, I measured the following approximate execution times:
First method (map + joined with arrays): 0.28 seconds.
Second method (map + joined with CollectionOfOne): 0.035 seconds.
Third method (using only map): 0.015 seconds.
converted to swift 5
extension Array {
func insert(separator: Element) -> [Element] {
(0 ..< 2 * count - 1).map { $0 % 2 == 0 ? self[$0/2] : separator }
}
}
Here is the original answer converted to Swift 3/4
let items = [1, 2, 3]
let sep = 0
let newItems = Array(items.map { [$0] }.joined(separator: [sep]))
print(newItems) // [1, 0, 2, 0, 3]