Swift. Sort array of struct - arrays

I need to order an array of struct.
I've try:
let aRes = self.aSoundTracks_Filtered.sort{ $0.st < $1.st }
provide error: Cannot invoke 'sort' with an argument list of type '((_, _) -> _)'
also try this:
let hasPrefixAndSuffixw = self.aSoundTracks_Filtered.sort( $0.st < $1.st )
provide error: Anonymous closure argument not contained in a closure
Any idea? :)
My aSoundTracks_Filtered was delared like this:
var aSoundTracks_Filtered = [SoundTrack]()
My struct was like this:
struct SoundTrack {
let sID : Int
let st : String
}

Your code works fine when you tested in a Playground in the following way:
struct SoundTrack {
let sID : Int
let st : String
}
var aSoundTracks_Filtered = [SoundTrack]()
aSoundTracks_Filtered.append(SoundTrack(sID: 1, st: "a"))
aSoundTracks_Filtered.append(SoundTrack(sID: 2, st: "b"))
aSoundTracks_Filtered.sort{ $0.st > $1.st } // [{sID 2, st "b"}, {sID 1, st "a"}]
But sort() sorts an array in-place. What you probably want to use is sorted(), which does not modify the original array and returns a new sorted array:
let aRes = aSoundTracks_Filtered.sorted{ $0.st > $1.st }
The above code is for Swift 1.2, for Swift 2.0 returning a sorted array is called "sort" again, but it is a (protocol extension) method now instead of a global function. I hope this help you.

So, it's actually pretty simple. However I wonder where the selfcomes from when you access the array. I don't know which class it belongs to, in case it would belong to the struct itself (I wouldn't know why but just in case) you'll have to mark the function as mutating as you're changing the value of a struct's attribute. The second thing is actually that you'll have to use curley brackets:
self.aSoundTracks_Filtered.sort({$0.st < $1.st})

Related

Check if optional array is empty in Swift

I realize there are a ton of questions on SO with answers about this but for some reason, I can't get any to work. All I want to do is test if an array has at least one member. For some reason, Apple has made this complicated in Swift, unlike Objective-C where you just tested if count>=1. The code crashes when the array is empty.
Here is my code:
let quotearray = myquotations?.quotations
if (quotearray?.isEmpty == false) {
let item = quotearray[ Int(arc4random_uniform( UInt32(quotearray.count))) ] //ERROR HERE
}
However, I get an error:
Value of optional type '[myChatVC.Quotation]?' must be unwrapped to refer to member 'subscript' of wrapped base type '[myChatVC.Quotation]'.
Neither of the fix-it options to chain or force unwrap solve the error. I have also tried:
if array != nil && array!. count > 0 and if let thearray = quotearray
but neither of those will work either
Thanks for any suggestions.
randomElement already exists, so don't reinvent the wheel:
var pepBoys: [String]? = ["manny", "moe", "jack"]
// ... imagine pepBoys might get set to nil or an empty array here ...
if let randomPepBoy = pepBoys?.randomElement() {
print(randomPepBoy)
}
The if let will fail safely if pepBoys is nil or empty.
You could unwrap the optional array and use that like this, also use the new Int.random(in:) syntax for generating random Ints:
if let unwrappedArray = quotearray,
!unwrappedArray.isEmpty {
let item = unwrappedArray[Int.random(in: 0..<unwrappedArray.count)]
}
check the first element is exist or not
var arr: [Int]? = [1, 2, 3, 4]
if let el = arr?.first{
print(el)
}
I would recommend use guard statement
guard let array = optionalArray, !array.isEmpty else { return }

How to order an object by a parameter that is an array of numbers (Swift)

I want to order an object by a parameter. But this parameter is not a value but an array of values.
class MyObject:{
var arrayOfDoubles: [Double]
}
I´ve solved how to order the param arrayOfDoubles
self.arrayOfDoubles.sorted(by: >)
My problem now is how to order the array myObjects by the param arrayOfDoubles
myObjects: [MyObject]
I´ve tried this solution, but it only works when the param is a number, not an array of numbers
myObjects.sorted(by: { $0.arrayOfDoubles > $1.arrayOfDoubles })
This might not be exactly what you want, because I can't figure out what you want (and I'm not sure you do either). But in general your problems will be over if you define a custom struct and make it Equatable and Comparable. Then you can just sort using > or < directly, like this:
struct Pair : Comparable {
let ix1:Int
let ix2:Int
init(_ ix1: Int, _ ix2:Int) {
self.ix1 = ix1; self.ix2 = ix2
}
static func ==(lhs:Pair, rhs:Pair) -> Bool {
return lhs.ix1 == rhs.ix1 && lhs.ix2 == rhs.ix2
}
static func <(lhs:Pair, rhs:Pair) -> Bool {
return lhs.ix1 < rhs.ix1 && lhs.ix2 < rhs.ix2
}
}
let array1 = [Pair(1,3), Pair(10,11), Pair(0,1)]
let array2 = array1.sorted(by:>)
// [{ix1 10, ix2 11}, {ix1 1, ix2 3}, {ix1 0, ix2 1}]
As I say, that's only an example; tweak it so that it says what you mean (if you even know what you mean).
For instance, if this Pair is now to be a property of another object type Obj, that's trivial in just the same way:
struct Obj {
let pair : Pair
}
let array3 = [Obj(pair:Pair(1,3)), Obj(pair:Pair(10,11)), Obj(pair:Pair(0,1))]
let array4 = array3.sorted {$0.pair > $1.pair}
I believe that's the sort of language your question says you'd like to use...

Map modify array of objects in Swift 2.2 (3.0)

I want to be able to modify my array of objects using map in Swift of the fly, without looping through each element.
Before here were able to do something like this (Described in more details here:
gnomes = gnomes.map { (var gnome: Gnome) -> Gnome in
gnome.age = 140
return gnome
}
Thanks for Erica Sadun and others, new proposals have gone through and we're now getting rid of C-style loops and using var inside the loop.
In my case I'm first getting a warning to remove the var in then an error my gnome is a constant (naturally)
My question is : How do we alter arrays inside a map or the new styled loops for that matter to be fully prepared for Swift 3.0?
If you want to keep that syntax, just use a (mutable) temporary variable
gnomes = gnomes.map { (gnome: Gnome) -> Gnome in
var mutableGnome = gnome
mutableGnome.age = 140
return mutableGnome
}
(Below follows the case where Gnome is a reference type; a class -- since you haven't showed us how you've defined Gnome. For the case where Gnome as value type (a struct), see #vadian:s answer)
The removal of var will not effect using .map to mutate mutable members of an array of reference type objects. I.e., you could simply use your old approach (omitting however, the var in the .map closure signature).
class Gnome {
var age = 42
}
var gnomes = [Gnome(), Gnome(), Gnome()]
gnomes = gnomes.map {
$0.age = 150
return $0
}
/* result */
gnomes.forEach { print($0.age) } // 3x 150
However, in case you just want to modify your original array rather than assigning the result of .map to a new array, .forEach might be a more appropriate choice than .map.
gnomes.forEach { $0.age = 140 }
/* result */
gnomes.forEach { print($0.age) } // 3x 140
Given:
struct Gnome {
var age: Int = 0
}
var gnomes = Array(count: 5, repeatedValue: Gnome())
... there are two decent options. The first is as #vadian put it:
gnomes = gnomes.map{
var gnome = $0
gnome.age = 70
return gnome
}
Whilst the second keeps control over "ageing" private and simplifies mapping at the point of call:
struct Gnome {
private(set) var age: Int = 0
func aged(age: Int) -> Gnome {
var gnome = self
gnome.age = age
// any other ageing related changes
return gnome
}
}
gnomes = gnomes.map{ $0.aged(140) }
Of course, reference types still have their place in programming, which may well be a better fit in this case. The friction we are experiencing here suggests that we are trying to treat these structures as if they were objects. If that is the behaviour you need, then you should consider implementing Gnome as a class.

Having array problems in Swift

I am learning how to build apps and working with Swift for this project.
I had a buddy help me pull data in from a website and it looks like he created classes with variables and mapped them to certain extensions (IE "Username") so when I call the variable data such as profile I would call it. The below uses luck_30 able to store "Stats.luck_30"
luck_30.text = profile.luck_30
So inside one of my variables that is in this "Profile" class is setup into an array. I can pull the array out of the class, but I can't seem to do for while statement replacing the [#] with a variable from the for command.
func aliveWorkers(profile: Profile) -> NSNumber{
var myworkers : Array = profile.workers!
//this test works and returns the proper value
var testworker: NSNumber = myworkers[0].alive!
println("The satus of the test worker is " + testworker.description)
/* This code is giving error "Could not find member alive" it does not ifor var
for ifor in myworkers{
var thisworker: NSNumber = myworkers[ifor].alive! as NSNumber
}
*/
return 42
}
Your variable ifor is not a counter, it is an actual object. You could do something like this:
for worker in myWorkers {
let workerIsAlive = worker.alive!
}
Alternatively, if you need the index,
for i in 0 ..< myWorkers.count {
let worker = myWorkers[i]
let workerIsAlive = worker.alive!
}
If you need both:
for (i, worker) in enumerate(myWorkers) {
let workerIsAlive = worker.alive!
}
And as a matter of style, I would stay away from NSNumber and use Int or Bool or whatever the data actually is. Also, it looks like the alive variable should not be optional, as you're unwrapping it everywhere. To avoid "mysterious" crashes later, you may want to think about making it a non-optional type.
when using a for in loop, your loop variable isn't an index, its the objects you're looping through. so..
func aliveWorkers() {
var myworkers = [1, 2, 3]
//this test works and returns the proper value
let testworker = myworkers[0]
print("The satus of the test worker is \(testworker)")
for ifor in myworkers {
print(ifor)
}
}
Notice a few things... you don't need to use + to concatenate those strings. you can just use string interpolation. \(variable) inserts the value of variable in the string.
Try to use let instead of var when you don't change the variable. You don't need to explicitly define type on variables either.

Using functions in arrays Swift

i use the following function to retrieve a random person from an array:
func getRandomPerson() -> String{
if(personArray.isEmpty){
return ""
} else {
var tempArray: [String] = []
for person in personArray{
tempArray += [person.getName()]
}
var unsignedArrayCount = UInt32(tempArray.count)
var unsignedRandomNumber = arc4random_uniform(unsignedArrayCount)
var randomNumber = Int(unsignedRandomNumber)
if tempArray.isEmpty {
return ""
} else {
return tempArray[randomNumber]
}
}
}
I would like to use this function inside an array of strings, Like this:
var theDares: [String] = ["Dare1 \(getRandomPerson())", "Dare2", "Dare3", "Dare4", "Dare5"]
But when i use the functions, it only runs the function once. Can you make the function run everytime you use the "Dare1" in this instance.
Thanks in advance
I think you are asking if you can set up your array so every time you fetch the object at index 0, it re-builds the value there.
The short answer is no. Your code is creating an array of strings, and the item at index 0 is built ONCE using a function call.
However, it is possible to make a custom class implement the subscript operator. You could create a custom object that looks like an array and allows you to index into it using an Int index. In response to the index operator you could run custom code that built and returned a random string.
Since it sounds like you're a beginning programmer creating a custom class the implements the subscript operator might be beyond your current abilities however.
Try like this:
let personArray = ["John", "Steve", "Tim"]
var randomPerson: String {
return personArray.isEmpty ? "" : personArray[Int(arc4random_uniform(UInt32(personArray.count)))]
}
println(randomPerson) // "Steve"

Resources