Summing columns in a 2D array in Swift - ios

I have a simple 2D array of integers named "round", with 5 elements on the horizontal and a variable number of "rows".
I want to calculate the total for each "column". Here's my code:
var totals = [Int] ()
for column in 0...4 {
for row in 0...round.count-1 {
totals[column] = round[row][column] + totals[column] }
}
I get a Playground "Fatal error: Index out of range"
In trying various options, it appears to be the "totals[column] = " assignment that throws the error, but I cannot determine why?

The problem is totals[column] since totals is an empty array it has no element at the index column.
It's similar to the following attempt:
var arr = [Int]()
arr[0] = 1 // <- fails, because there is no element at index 0
To fix this issue, you can initialize totals with zeros for the number of elements you want to store in the array:
var totals = Array(repeating: 0, count: round[0].count)
Or even simpler (but less dynamic):
var totals = [0, 0, 0, 0, 0]

Related

Pairing duplicate elements in an array

I am trying to pair the duplicate elements of an array and count the pairs.
When given array is : [10, 20, 20, 10, 10, 30, 50, 10, 20], I'm expecting numberOfPairs to be 3. Because there are 2 pairs of 10s and 1 pair of 20.
My "if condition" is checking if current element's index is first index or not. If it is not the last index, it means that there is a duplicate of the current element. So I'am adding 1 to numberOfPairs.
For input [10, 20, 20, 10, 10, 30, 50, 10, 20], my numberOfPairs is 2 but it should be 3.
For input [1 1 3 1 2 1 3 3 3 3], myNumberOfPairs is not printing at all? But instead it should be 4.
My What am I missing here?
func sockMerchant(n: Int, ar: [Int]) -> Int {
// Write your code here
var array = ar
var numberOfPairs = 0
for i in 0..<array.count {
var element = array[i]
let indexOfLastElement = array.lastIndex(of: element)
let indexOfFirstElement = array.firstIndex(of: element)
print("indexOfLastElement is \(indexOfLastElement)")
print("indexOfFirstElement is \(indexOfFirstElement)")
if indexOfFirstElement != indexOfLastElement {
numberOfPairs += 1
array.remove(at: indexOfFirstElement!)
array.remove(at: indexOfLastElement!)
continue
}
return numberOfPairs
}
return numberOfPairs
}
You're mutating your array by calling remove(at:) at the same time as you're accessing it which is why you're having these weird side effects.
I assume you're trying to solve a Leetcode task (or something similar), so I won't provide a solution upfront. My suggestion for you is to think of an algorithm that doesn't involve changing the contents of the List while you're reading these contents of that same List.
I'm agree with #MartinR that in such cases you should place breakpoints and go throught your code line by line, glad you've found your mistake by yourself.
But also in terms of performance, lastIndex and firstIndex are very heavy operations, because they may go thought all items and find nothing, which makes Big O notation of your algorithm around O(log n). In such cases dictionary is widely used(if you're not much limited with the space).
You can use value as a key and count as a value for a dictionary and count all items, then just sum like this:
func sockMerchant(ar: [Int]) -> Int {
ar.reduce(into: [Int:Int]()) { map, value in
map[value, default: 0] += 1
}.reduce(0) { sum, count in
sum + count.value / 2
}
}
So, I've solved the problem as below, thanks to #Vym and #Martin R.
func sockMerchant(n: Int, ar: [Int]) -> Int {
// Write your code here
var array = ar
var numberOfPairs = 0
var newArray = [Int]()
var done = false
for i in 0..<array.count {
let element = array[i]
let indexOfLastElement = array.lastIndex(of: element)
let indexOfFirstElement = array.firstIndex(of: element)
if indexOfFirstElement != indexOfLastElement {
newArray.append(element)
numberOfPairs = newArray.count/2
done = true
}
}
if done == true {
return numberOfPairs
}
return numberOfPairs
}

how to store values in a 1D array into a 2D array in Swift 4

Hi I would like to store values of a 1D array into a 2D array.
My 1D array has 50 elements and I want to store it in a 5x10 array, but whenever I do that, it always gives me a "Index out of range" error
Any help would be appreciated thanks!
var info2d = [[String]]()
var dataArray = outputdata.components(separatedBy: ";")
for j in 0...10 {
for i in 0...5 {
info2d[i][j] = dataArray[(j)*5+i]
print(info2d[i][j])
}
}
Lots of error in your code.
info2d must be initialised with default values before using it by index
// initialising 2d array with empty string value
var info2d = [[String]](repeating: [String](repeating: "", count: 10), count: 5)
Secondly for loop with ... includes the last value too, use ..<
for j in 0..<10 {
//...
}
Thirdly (j)*5+i is incorrect too.
Better Read how to use arrays, collections and for loop in swift.
https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html
https://docs.swift.org/swift-book/LanguageGuide/CollectionTypes.html
I would make use of ArraySlice for this.
var arr2D = [[String]]()
for i in 0..<5 {
let start = i * 10
let end = start + 10
let slice = dataArray[start..<end] //Create an ArraySlice
arr2D.append(Array(slice)) //Create new Array from ArraySlice
}

Finding and combining duplicate entries in an array

Im new here so correct me if I've formatted this incorrectly (also new to swift) but basically what I'm trying to do is take an array of dates and numbers and if any of the dates are the same combine the numbers into one entry.
so this
//This is how i format the data after i pull it from core data
var dateAndEntry = [(String, Double)]
//i've split them into two seperate arrays for sorting, but I feel like theres a better way i don't know
var dates = ["01/01/2016", "02/01/2016", "02/01/2016", "04/01/2016", "05/01/2016", "06/01/2016","07/01/2016","07/01/2016"]
var entries = [-14,2,8,9,-1,8,25,6]
becomes this
var dates = ["01/01/2016", "02/01/2016", "04/01/2016", "05/01/2016", "06/01/2016","07/01/2016"]
var entries = [-14,10,9,-1,8,19]
I've tried doing this but i can only get it so that it makes a new array that only contains the new values rather than allowing me to get the duplicated values, combine, insert at index then delete original entries in the two arrays.
func combineDuplicates(dates: [String]) -> [String]{
var output: [String] = []
var checked = Set<String>()
for date in dates {
if !checked.contains(date) {
checked.insert(date)
output.append(date)
}
}
print(output)
return output
}
let sorted = combineDuplicates(dates)
print(sorted)
and yes i have looked on google and here for answers but turned up nothing.
Any solutions, explanations, help, pointers or references to other questions or sources I may have missed would all be greatly appreciated.
This will get you a dictionary with keys the dates and values the sum of entries for each date:
dates.enumerate().reduce([String:Int]()) { dict, item in
var dict = dict
dict[item.1] = (dict[item.1] ?? 0) + entries[item.0]
return dict
}
// ["06/01/2016": 8, "04/01/2016": 9, "01/01/2016": -14, "05/01/2016": -1, "07/01/2016": 31, "02/01/2016": 10]

NSRange array of odd or even count

I have an array of 977 of data, I've been trying to split it to 20 section in UITableView but i cannot get it correct, i am trying to do it dynamically. like if i got an array of 312 or 32 or 545 the equation should divide it, and add the last odd elements in array, I'm placing the new data in array of arrays.
So here is what I'm doing :
var dataof977 = Mydata()
var mutA = NSMutableArray()
for (var i = 0; i < 19; i++)
{
var halfArray : NSArray!
var theRange = NSRange()
theRange.location = i*19;
theRange.length = dataof977.afa.count / 19
halfArray = dataof977.afa.subarrayWithRange(theRange)
mutA.addObject(halfArray)
}
Note : dataof977 is reference of class and afa is a String array.
What am i missing here ?s
Three things:
You need to start each location where the previous left off. To do this, introduce a location variable to keep track of where you are in the original array.
Some of your sections will need more items since your count might not be a multiple of 20. I think your best best is to give the first n sections an extra item to make up for the leftovers.
Your loop needs to iterate 20 times, not 19. I have changed it to use for in which is better Swift style.
var mutA = NSMutableArray()
let sublength = dataof977.afa.count / 20
let leftovers = dataof977.afa.count % 20
// location of each new subarray
var location = 0
for i in 0..<20
{
var length = sublength
// The first sections will have 1 more each
if i < leftovers {
length++
}
let theRange = NSMakeRange(location, length)
let halfArray = dataof977.afa.subarrayWithRange(theRange)
mutA.addObject(halfArray)
// move location up past the items we just added
location += length
}
If you have the possibility to work with Swift arrays instead of NSArray, you can use stride to iterate by steps and divide an array in equal parts with the remainder elements in the last array:
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
extension Array {
func splitBy(subSize: Int) -> [[Element]] {
return 0.stride(to: self.count, by: subSize).map { startIndex in
let endIndex = startIndex.advancedBy(subSize, limit: self.count)
return Array(self[startIndex ..< endIndex])
}
}
}
let chunks = arr.splitBy(5)
print(chunks) // [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12]]
Note: this is for Swift 2.
You are only doing 19 iterations, not 20.
for var i = 0; i < 20; i++
You are taking one 19th of the data count, not one 20th. You are repeating the length calculation 19 times in the loop, which is redundant.
It would be easier to dispense with NSRange. Just iterate though all array elements, keep a counter up to the pre-calculate subarray size, and once it reaches the critical number, reset it to zero and start a new subarray to add to your result array.
This will presumably perform better if you use Swift arrays, but this is not strictly necessary.

How do I merge and format arrays in Swift? (X and Y coordinate arrays)

I am attempting to merge two arrays in specific formatting in order to create an array of x and y coordinates that will be used to create a graph. I have separate arrays of X-Values and Y-Values in [Double] format, for example:
var xAxis = [1, 2, 3, 4]
var yAxis = [2, 3, 4, 5]
I wish to merge these such that they are presented in the following format:
var chartPoints = [(1,2),(2,3),(3,4),(4,5)]
or more generally:
chartPoints = [(x,y)]
I have tried a few different options, such as the append and extend methods to no luck as this does not sort the arrays or format them in the method required.
How can I merge the two x and y axis arrays to a singular formatted array?
You can use the zip global function, which, given 2 sequences, returns a sequence of tuples:
let pointsSequence = zip(xAxis, yAxis)
You can then obtain an array of tuples by using the proper init:
let chartPoints = Array(pointsSequence)
Each element of the array is a (x, y) tuple - but values are unnamed, so you can access their individual values by index:
let point = chartPoints[0]
point.0 // This is the 1st element of the tuple
point.1 // This is the 2nd element of the tuple
If you prefer the tuple values to be named, you can make the tuple type explicit:
let chartPoints: [(x: Int, y: Int)] = Array(pointsSequence)
and with that you can access using either the index (as in the example above) or using their explicit names:
let point = chartPoints[0]
point.x
point.y
var xAxis = [1,2,3,4]
var yAxis = [2,3,4,5]
var chartPoints: [(x:Int,y:Int)] = Array()
if(xAxis.count == yAxis.count){
for i in 0...xAxis.count-1 {
let chartPoint = (x:xAxis[i],y:yAxis[i])
chartPoints.append(chartPoint)
}
}
for pt in chartPoints{
print("\(pt)")
}
result:
(1, 2)
(2, 3)
(3, 4)
(4, 5)

Resources