2D Arrays in Swift 3 - ios

I am trying to populate an array with graph coordinates x and y. At the moment this is what I have:
let chartPoints1 = [(1, 1), (2, 2), (3, 3), (4, 4)].map{ChartPoint(x: ChartAxisValueInt($0.0, labelSettings: labelSettings), y: ChartAxisValueInt($0.1))}
However, I want to add the coordinates from another array by looping through that array, something like this:
let tasks = DatabaseManager.getTasks("Tasks")
let count: Int! = tasks?.count
for i in 1...count {
chartPoints1.append(i, tasks[i].date)
}
but I can't seem to figure out exactly what kind of array chartPoints1 is and how the map function works.

You don't have a 2d array. You first have an array of tuples, which gets mapped to an array of ChartPoints. So, in your append, I think you're looking for something like
chartPoints1.append(ChartPoint(...))
To clarify further, a 2d array is an array of arrays, which might look like:
[[1, 1], [2, 2], [3, 3]]
Each element of your array is a tuple. So, when you call map, $0 represents the current tuple (say, for instance, (1, 1)). Tuple syntax lets you get the first thing in the tuple by $0.0, the second thing by $0.1 and so forth. With that in mind, I think you should be able to see how you're constructing a ChartPoint with each element, so your new array has type [ChartPoint].

Related

Deinterlace a vector using vDSP

Let's say I have a vector:
let input: [Float] = [1, 2, 3, 4, 5, 6, 7, 8, ...]
What I'd like to do is deinterlace this vector by selecting every other value to produce 2 new vectors as output, as follows:
[1, 3, 5, 7, ...]
[2, 4, 6, 8, ...]
What's the best way to do this in vDSP?
The tool you want here is vDSP.convert(interleavedComplexVector:toSplitComplexVector:). Don't let the "complex vector" confuse you. It doesn't matter if these are "complex" or not. An "interleaved complex vector" is just "a series of even and odd values." And a "split complex vector" is just "a struct containing a list of evens and a list of odds." These are sometimes interpreted as real and imaginary components, but that interpretation has nothing to do with how convert works (and often has nothing to do with how these values are used in practice).
So assuming a [Float] like:
let input: [Float] = [1, 2, 3, 4, 5, 6, 7, 8]
And two output lists ("vectors") like:
var evens: [Float] = Array(repeating: 0, count: input.count / 2)
var odds = evens
You can split them up this way:
evens.withUnsafeMutableBufferPointer { evenPtr in
odds.withUnsafeMutableBufferPointer { oddPtr in
var split = DSPSplitComplex(realp: evenPtr.baseAddress!,
imagp: oddPtr.baseAddress!)
input.withUnsafeBytes {
vDSP.convert(interleavedComplexVector: Array($0.bindMemory(to: DSPComplex.self)),
toSplitComplexVector: &split)
}
}
}
// At this point, evens and odds are filled in.
This is intentionally modeled closely on Apple's example code for setting up an FFT.
If you happen to need more values split up this way (particularly 4 values), take a look at vImageConvert_ARGBFFFFtoPlanarF and related functions. Just like "complex" really just means "two floats," "ARGBFFFF" just means "4 floats." Numbers are just numbers and sometimes the function you need happens to be named based on another use case.

Call on a String as an Array

I have been stuck on a problem for a couple days now and I'm not sure how to word it, so I haven't had much luck searching for an answer hoping you can help!
I have an array of 20 arrays which is the same as my array of 20 strings, when a button is clicked the array changes to the name of the selected button, I can change it to a string very easily with:
newArray = oldArray[0]
But cannot find a way to insert the string name as the new array name, if anyone has any advice I'd be glad, thanks!
newArray = [oldArray[0]]
Just creates an array with one string in, I have been looking for a function something like:
newArray = Array(named: oldArray [0])
but not sure if it exists.
If you want to insert on some specific index then use insert like this:
var newArr = [String]()
newArr.insert("jogendar", at: 0) /// Removes and returns the element at the specified position.
And if you want to add at the end then use append like this:
var newArr = [String]()
newArr.append("jogendar") ///Adds the elements of a sequence to the end of the array.
If you want to change the name of the button when selected then you don't need to maintain the array, you can set the title of button for states like this:
let btn = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
btn.setTitle("jogendar_defautl", for: UIControlState.normal)
btn.setTitle("jogendar_selected", for: UIControlState.selected)
And when you want to select the button then button name auto change according to selected state:
btn.isSelected = !btn.isSelected
This is not an answer as such, you do not provide enough detail for that, but let's see if we can help you onto the right track. You wrote:
I have been looking for a function something like:
newArray = Array(named: oldArray [0])
This does not exist because arrays (and other values) do not have names. You appear to be confusing variable names and values, they are very different things. For example, the expression:
[0, 1, 8, 27, 64]
produces an array value containing five elements, it has no name it is just a value. The value could be assigned to a variable:
var cubes = [0, 1, 8, 27, 64]
Now we have a variable with the name cubes whose current value is the array. The above statement has both declared a variable, cubes, given it a type, [Int], and assigned it an initial value, [0, 1, 8, 27, 64]. It has not named the value, the value can be copied into another variable:
var anotherVariable = cubes
After the above you have two variables, cubes and anotherVariable, each which currently has the same value. Values are not shared, you can alter one of the values:
anotherVariable[0] = 42
and now anotherVariable contains the value [42, 1, 8, 27, 64] while cubes still contains the value [0, 1, 8, 27, 64].
OK, back to your question, you wrote:
I have an array of 20 arrays which is the same as my array of 20 strings...
What you appear to be describing is something along the lines of:
var myArrays = [ [0, 1, 4, 9, 16], [0, 1, 8, 27, 64] ]
var myNames = [ "squares", "cubes" ]
and you have buttons with labels squares and cubes. What you appear to be attempting is to go from a click on a button to an element of myArrays via the myNames array - which is where you "naming" of values is coming from.
To map a "name" to a "array" you should use a dictionary, which is a collection keys, your names, to values, your arrays:
let myCollection = [ "squares":[0, 1, 4, 9, 16], "cubes":[0, 1, 8, 27, 64] ]
This declares a constant (the use of let rather than var) dictionary whose keys are strings and values arrays. So you effectively have a collection of "named arrays".
You can now select an array for this collection by name using a statement along the lines of:
var currentArray = myCollection[currentButtonTitle]
where currentButtonTitle has previously been set to the title of the button you clicked.
HTH

Init array with range of Int-s, can someone explain this one-liner?

I'd like to initialise an array of Int-s with a series of numbers. Example [0, 1, 2, 3, 4, 5]. I know there are some better way than using the for loop and I've fond this one-liner that works var values: [Int] = (0...4).map() { $0 }. But I just can't understand what's going on here. I understand I have a range 0...4. Is this range in brackets behaving like closure? And what does the map() function do? I can't find it in the reference. And also $0 is something I can't understand. Can someone explain what's going on here?
var values: [Int] = (0...4).map() { $0 }
// result: [0, 1, 2, 3, 4]
.I'm still using Swift 1.2
(0...4)
creates a Range
.map() { $0 }
applies a transformation (which here is no transformation)to each element of that range and returns an array containing the results of that transformation, which is a [Int]. The reference for map, at the bottom.
And the $0 means the first parameter of the method, so $1 would be the second parameter and so on. And here $0 means first 0, then 1...
And for example if you want to create 2, 4, 6, you could use map like this:
var values = (1...3).map { $0 * 2 }
so you multiply first 1 * 2, then 2 * 2 finally 3 * 2.
The brackets surrounding the range are only used to use methods of the Range type, in this case map.
This method takes each elements of your collection (a range in your code), pass it to a closure or block ({ $0 }) and the return value of the closure is used in the collection returned by map.
Swift syntax allow to write closure after the brackets of map(), if the closure is very simple you can even omit return and parameters name which will be called $x where x is a zero-based progressive number, in your case $0 represents the number of your range.
If we expand your code to make it more clear we get
let range = 0...4
bar values: [Int] = range.map({ (i: Int) -> Int in
return i
})

Percent Similarity of an Array Swift

Say I have two arrays:
var arrayOne = ["Hi", "Hello", "Hey", "Howdy"]
var arrayOne = ["Hi", "Hello", "Hey", "Not Howdy"]
What could I do to compare how similar the array elements are? As in a function that would return 75% Because the first three elements are the same but the last element are not. The arrays I'm using in my project are strings but they will almost entirely match except for a few elements. I need to see What percent the differences are. Any ideas?
let arrayOne = ["Hi", "Hello", "Hey", "Howdy"]
let arrayTwo = ["Hi", "Hello", "Hey", "Not Howdy"]
var matches = 0
for (index, item) in enumerate(arrayOne) {
if item == arrayTwo[index] {
matches++
}
}
Double(matches) / Double(arrayOne.count) // 0.75
Both of these algorithms use the idea that if you have two different length arrays, the highest similarity you can have is short length / long length, meaning that the difference in the array lengths are counted as not matching.
You could add all of the terms to a set and then make your percentage the size of the set / length of longest array.
You could sort both arrays and then do a loop with an index variable for each array and compare the values at the two indices, advancing the index for the array that has the "lower" value in the comparison, or increment a counter if they are equivalent. Your percentage would be the counter / length of longest array.
One thing to think about though is how you want to measure similarity in weird cases. Suppose you have two arrays: [1, 2, 3, 4, 5] and [1, 1, 1, 1, 1]. I don't know whether you would want to say they are completely similar, since all of the elements in the second array are in the first array, or if they only have a similarity of 20% because once the 1 in the first array is "used", it can't be used again.
Just some thoughts.
maybe something like this? (written off top of my head so havent checked if it actually compiles)
var arrayOne = ["Hi", "Hello", "Hey", "Howdy"]
var arrayTwo = ["Hi", "Hello", "Hey", "Not Howdy"]
var matches = 0
for i in 0...arrayOne.count { //assuming the arrays are always the same length
if arrayOne[i] == arrayTwo[i]{
matches++
}
}
var percent = matches / arrayOne.count
A good way to measure the similarity of 2 arrays is to iterate all elements of an array, and keep a cursor on the 2nd array, such that at any time the current element of the iterated array is not greater than the element at the cursor position.
As you may argue, this algorithm require elements to be comparable, and as such it works if the arrays type implements the Comparable interface.
I've worked on a generic function that perform that calculation, here it is:
func compare<T: Comparable>(var lhs: [T], var rhs: [T]) -> (matches: Int, total: Int) {
lhs.sort { $0 < $1 } // Inline sort
rhs.sort { $0 < $1 } // Inline sort
var matches = 0
var rightSequence = SequenceOf(rhs).generate()
var right = rightSequence.next()
for left in lhs {
while right != nil && left > right {
right = rightSequence.next()
}
if left == right {
++matches
right = rightSequence.next()
}
}
return (matches: matches, total: max(lhs.count, rhs.count))
}
Let me say that the implementation can probably be optimized, but my goal here is to show the algorithm, not to provide its best implementation.
The first thing to do is to obtain a sorted version of each of the 2 arrays - for simplicity, I have declared both parameters as var, which allows me to edit them, leaving all changes in the local scope. That's way I am using in-place sort.
A sequence on the 2nd array is created, called rightSequence, and the first element is extracted, copied into the right variable.
Then the first array is iterated over - for each element, the sequence is advanced to the next element until the left element is not greater than the right one.
Once this is done, left and right are compared for equality, in which case the counter of matches is incremented.
The algorithm works for arrays having repetitions, different sizes, etc.

iOS Swift - Reduce function

I have a piece of code in SWIFT that I don't understand:
var peers: [String:NSSet] = [:]
for s in squares {
var ps = reduce(units[s]!, NSMutableSet()) { set, u in
set.addObjectsFromArray(u)
return set
}
ps.removeObject(s)
peers[s] = ps
}
squares is an array of String.
So far I have realized that peers probably is a key/value data structure with keys of String and values of NSSet. NSSet is similar to Array but it cannot accept duplicate items. The main part that I don't understand is actually the reduce function. Any explanation or instructive article/webpage is appreciated.
reduce is a method that's used to reduce an array into single value using the operator that you provide to construct the final result. Most demonstrations of this available in tutorials use + or * to reduce an array of numbers into a single sum or multiplication result.
The method you're using takes the input array units[s] and an initial value NSMutableSet() (an empty set), then applies the closure to each element in sequence.
Your code seems to indicate that the elements of units[s] are again arrays; so your data might look something like this:
units[s]: [
[1, 2, 3, 4],
[5, 6, 7, 8],
[1, 3, 5, 7]
]
Making ps be:
ps: [ 1, 2, 3, 4, 5, 6, 7, 8 ]
after your reduce call.
var ps = reduce(units[s]!, NSMutableSet()) { set, u in
set.addObjectsFromArray(u)
return set
}
Reduce combines elements from array in the first parameter (units[s] should be an array) into second parameter (here NSMutableSet). The code in curly brackets that follows tells how to combine the elements. The "set" and "u" refer to the units[s] and the NSMutable set. So it takes each element in units[s] and adds them to the NSMutableSet.

Resources