How to sort in Swift - ios

Looked online to get a better understanding of both Xcode and Swift and I've tried some things out and get errors. I'm using Xcode 8.2.1. I've tried using sort, but I'm for the version of swift I have it's sorted(by:) and I haven't gotten it to work so far. If you can please explain what I need to do and maybe leave an example that would be much appreciated!
There are 4 tasks I'm supposed to do.
Assign a list of unique random numbers to 5 variables and 5 constants. (Not sure if the way I did it was right or if I should use
Int(arc4random_uniform(50)).
Place them in an array
Sort by ascending order
Store them in a dictionary using key values to retrieve the highest and lowest number easily.
I'll leave my code here.

Yes, you should probably use arc4random_uniform to generate your random numbers.
If you must store your results into a dictionary (this is silly, as Rob points out in his comment) I would suggest using a dictionary of type [Int:Int]. That way you can use the array indexes as the keys.
Thus your dictionary declaration would be something like this:
var resultsDict: [Int:Int] = [:]
You could populate your dictionary using
for (index, value) in array.enumerated {
resultsDict[index] = value
}
Then you could fetch the first result using
resultsDict[0]
And fetch the last result using
resultsDict[resultsDict.count - 1]

from use case it makes no sense place them in variables and constants
my solution would be:
// 1. Assign a list of unique random numbers to 5 variables and 5 constants. why variables and constants?
// 2. Place them in an array
var arr = (1...10).map{ _ in Int(arc4random_uniform(50)) }
print(arr) // -> [19, 41, 27, 47, 12, 38, 38, 48, 5, 41]
// 3. Sort by ascending order
arr.sort()
print(arr) // -> [5, 12, 19, 27, 38, 38, 41, 41, 47, 48]
// 4. to retrieve the highest and lowest number easily
print(arr.first!) // -> 5
print(arr.last!) // -> 48
or in short:
var arr2 = (1...10).map{ _ in Int(arc4random_uniform(50)) }.sorted()
print(arr2) // -> [4, 5, 14, 20, 21, 27, 30, 37, 39, 43]
print(arr2.first!) // -> 4
print(arr2.last!) // -> 43

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.

Swift Arrays: Keeping the order while filtering an array using another

I have an array as a list of numbers. In another smaller array I hold some numbers (in a different order) and I'd like to filter my first array using the values in the second array.
My arrays:
let allNumbers = [50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200]
let someNumbers = [100, 90, 120, 200] // unordered
When I use filter method or loop through the values of the first array, I can get the correct values but the order of the elements is not same with my second array but the first -naturally.
Method 1: filter method, losing order
let filtered = allNumbers.filter { someNumbers.contains($0) } // Runs 17 times
print(filtered) // "[90, 100, 120, 200]" (wrong order)
Method 2: Looping through first array, losing order
var filteredWithLoop: [Int] = []
for number in allNumbers { // Runs 16 Times
if someNumbers.contains(number) {
filteredWithLoop.append(number)
}
}
print(filteredWithLoop) // "[90, 100, 120, 200]" (wrong order)
Hack: I can work this around by filtering the first array when I'm looping through the second, like this:
var filteredUglyWay: [Int] = []
for number in someNumbers {
if let alone = (allNumbers.filter { $0 == number }).first { // Runs 4 * 16 Times
filteredUglyWay.append(alone)
}
}
print(filteredUglyWay) // "[100, 90, 120, 200]" (correct order)
But this feels more like a hack rather than a solution to me especially considering that the loop-ish filter method is called in a loop.
Is there a better approach for this or is this just how it's supposed to be?
Important note: The first array is actually a representation to make the situation more understandable. In my real implementation, first array is holding some objects and the second array is just the ID list of some objects (like favorites of the user) so each time I fetch the whole data, I am trying to filter the favorite objects according to this ID list.
A possible solution:
Filter, then sort.
let filtered = allNumbers.filtered({ someNumbers.contains($0) })
let filteredAndSorted = filtered.sorted(by: { someNumbers.index(of: $0)! < someNumbers.index(of: $1)! })
Side note, since filtered is composed of data only in someNumbers, the fore unwrap shouldn't create a crash.
why not to try updated method 2
Method 2 UPDATED: Looping through second array
var filteredWithLoop: [Int] = []
for number in someNumbers { // Runs 4 Times
if allNumbers.contains(number) {
filteredWithLoop.append(number)
} // IF OBJECT IS NOT THERE IN FIRST ARRAY IT WILL BE AUTOMATICALLY DISCARDED
}
print(filteredWithLoop) // "[100, 90, 120, 200]" (proper order)
You can do this:
let filtered = someNumbers.filter { allNumbers.contains($0) }
print(filtered) // Prints [100, 90, 120, 200]
It's probably less efficient when allNumbers is much larger than someNumbers, but if efficiency isn't an issue here, it seems like this is the most neat solution to me.

I unable to set Custom Label for X Axis by using with SwiftChart Library

I integrated SwiftChart library through Cocoapods, and successfully I can able to use swiftChart properties for the line chart. But I want to customize the X-Axis labels as I have some dates(2018/06/12, 2018/06/13, etc..) to display on X-Axis. Could you please guide me on this.
I have integrated the library for my requirement
https://github.com/gpbl/SwiftChart.
You only should read the documentation, I found this code and it may be what you need:
// Use `xLabels` to add more labels, even if empty
chart.xLabels = [0, 3, 6, 9, 12, 15, 18, 21, 24]
// Format the labels with a unit
chart.xLabelsFormatter = { String(Int(round($1))) + "h" }
The before code, it's for adding 'h', on each value, you can make a function to solve it with your requirements.
EDIT
You can make a parallel array, with your required dates i.e ["2018/06/12", "2018/06/13", "2018/06/13","2018/06/13","2018/06/13"] and the array for xLabels i.e [3, 5, 12, 5, 34].. both with the same number of items, and you can replace value for the one this array of dates on the same index..
You have the index on the sugar syntax $0 within the chart.xLabelsFormatter = { }
open var xLabelsFormatter = { (labelIndex: Int, labelValue: Double) -> String in
String(Int(labelValue))
}
Finally, I solved my problem by creating the separate array which contains the same count of actual array objects and used that array to display on x-axis label.
let mainArray = [0, 3, 6, 9, 12,]
let displayArray = ["01/03/18", "012/03/18", "15/03/18", "17/03/18", "20/03/18"]
self.chartView.xLabels = mainArray
self.chartView.xLabelsFormatter = { (labelIndex: Int, labelValue: Double) -> String in
return displayArray[labelIndex]
} self.chartView.add(series)

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

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