Have a little Problem and can´t find a working solution :(
I have a NSMutableArray like:
{
Entfernung = 129521;
"Event_DATE" = "2014-03-23";
"Event_ID" = 1;
"Event_KAT" = 1;
"Event_NAME" = achtzehn;
},
{
Entfernung = 112143;
"Event_DATE" = "2014-03-24";
"Event_ID" = 2;
"Event_KAT" = 2;
"Event_NAME" = neunzehn;
}
How can i sort this Array with the object "Entfernung"?
Thx 4 help!
Gerhard
Try something like this;
NSArray *stuff = .... //your array here;
NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:#"Entfernung" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
//depending on the number stored in the string, you might need the floatValue or doubleValue instead
NSNumber *num1 = #([(NSString*)obj1 integerValue]);
NSNumber *num2 = #([(NSString*)obj2 integerValue]);
return [num1 compare:num2];
}];
NSArray *sortedStuff = [[stuff sortedArrayUsingDescriptors:#[sorter]];
The easiest I'd say would be to define a compare method on Entfernung class and then use - (void)sortUsingSelector:(SEL)comparator If you already have a function which accepts two objects (say your NSDictionary object) then I'd do the sort like this - (void)sortUsingFunction:(NSInteger (*)(id, id, void *))compare context:(void *)context
Give a man a fish, and he can eat today. Tell him how to fish, and he has to do the work himself for the rest of his life...
In Xcode, look at the help menu. In the help menu, you find an item "Documentation and API reference". There you type in "NSMutableArray", then you search for "sort". Which gives you five methods:
– sortUsingDescriptors:
– sortUsingComparator:
– sortWithOptions:usingComparator:
– sortUsingFunction:context:
– sortUsingSelector:
You can click on each one and read the description. The most straightforward to use is sortUsingComparator: which comes with a nice bit of sample code that you adapt for your purposes.
Related
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.
I'm a newbie to swift and believe me I've searched and searched for an answer already. I want to create UISliders that get their values from an array of numbers in Swift. Its a camera app so the example array should be obvious.
#IBAction func isoValueChanged(sender: UISlider) {
let isoArray = ["24", "32", "50","64","80","100","125","160","200","250","320","400","500","640","720","800","1000","1250","1600","1800"] // available iPhone 6s ISO settings I believe
let currentValue = // What do I need?
isoText.text = "\(currentValue)"
}
Even harder would be representing shutter speeds from 1/1000 - 32!
From what I see out there this is not an easy one because there is no mathematical representation to calc from the array. Is it even possible?
I'm not quite sure I understand what you want this for but I'm guessing this is right.
// Global Variable or something like this (accessible from multiple functions)
let isoArray = ["24", "32", "50","64","80","100","125","160","200","250","320","400","500","640","720","800","1000","1250","1600","1800"] // available iPhone 6s ISO settings I believe
func functionThatCreatesTheSliderYo(...) {
slider.minimumValue = 0
slider.maximumValue = isoArray.count
slider.continuous = false
}
#IBAction func isoValueChanged(sender: UISlider) {
// instead of Int(val) you may want to round(val) for a better UI
let currentValue = isoArray[Int(sender.value)]
isoText.text = "\(currentValue)"
}
This works for me
#IBAction func isoValueChanged(sender: UISlider) {
let isoArray = ["24", "32", "50","64","80","100","125","160","200","250","320","400","500","640","720","800","1000","1250","1600","1800"]
let currentValue = isoArray[Int(sender.value)]
isoText.text = "\(currentValue)"
}
So simple as it should be in Swift. Many thanks to Ty. Be sure to see the chat though.
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})
I am currently learning swift and am experimenting with data structures. In may code I have certain routines with a name(String) and several tasks(Array of Strings). These values are in a structure.
So I am trying to add another value to the array after it has been initialized. My code is actually working, however I really think it very weird and odd and DO NOT think, that it is the way it should be done.
var routineMgr: routineManager = routineManager();
struct routine{
var name = "Name";
var tasks = [String]();
}
class routineManager: NSObject {
var routines = [routine]();
func addTask(name: String, desc: String){
//init routines with name and an array with certain values, here "Hallo" & "Moin"
routines.append(routine(name: name, tasks: ["Hallo","Moin"]));
//so i just put this part here to make the example shorter, but it would be in ad different function to make more sense
//adding a new value ("Salut") to the tasks array in the first routine
//getting current array
var tempArray = routines[0].tasks;
//appending new value to current value
tempArray.append("Salut");
//replacing old routine with a copy (same name), but the new array (with the appended salut)
routines[0] = routine(name: routines[0].name, tasks: tempArray);
}
}
I have tried some (to me) "more correct" ways, like:
routines[0].tasks.append("Salut");
But I always got tons of errors, which I also did not understand.
So my question now: How is it actually done correctly? And why does the second way not work?
Your help and advice is really appreciated!
You can create a function to append the values in the struct (that is what I would do). You can even use it to validade values or anything else you need to do before append, it can also return a boolean to let your code know if the value was successfully appended or not
var routineMgr: routineManager = routineManager();
struct routine{
var name = "Name";
var tasks = [String]();
mutating func addTask(task: String){
tasks.append(task)
}
}
class routineManager: NSObject {
var routines = [routine]();
func addTask(name: String, desc: String){
routines.append(routine(name: name, tasks: ["Hallo","Moin"]));
routines[0].addTask("Salut")
}
}
I hope that helps
Getting hugely frustrated trying to translate objective c to swift. I have the following code that works for objective c.
NSMutableArray *path = [NSMutableArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Sequence List" ofType:#"plist"]];
//Shuffle the array of questions
numberSequenceList = [self shuffleArray:path];
currentQuestion = currentQuestion + 1;
if (Round==1) {
//Take first object in shuffled array as the first question
NSMutableArray *firstQuestion = [[NSMutableArray alloc] initWithArray:[numberSequenceList objectAtIndex:0]];
//Find question and populate text view
NSString *string = [firstQuestion objectAtIndex:0];
self.lblNumber.text = string;
//Find and store the answer
NSString *findAnswer = [firstQuestion objectAtIndex:1];
Answer = [findAnswer intValue];
}
But I can't seem to get this to work in swift. I can pull out the contents of the plist using
var path = NSBundle.mainBundle().pathForResource("Sequence List", ofType: "plist")
But I can't see that there is an equivalent to objectAtIndex in swift. If I try the following I get an error message advising "string does not have a member named subscript", which apparently means I need to unwrap path.
let firstQuestion = path[0]
The methods you are calling, like NSBundle.mainBundle().pathForResource, return optionals, because they might fail. In Objective-C, that failure is indicated by a nil, whereas Swift uses optionals.
So in your example:
var path = NSBundle.mainBundle().pathForResource("Sequence List", ofType: "plist")
path is of type Optional<String> (or String?) and not of type String. Optional<String> doesn’t have a subscript method (i.e. doesn’t support [ ]). To use the string within, you have to check if the optional contains a value (i.e. the call to pathForResource was successful):
// the if let syntax checks if the optional contains a valid
if let path = NSBundle.mainBundle().pathForResource("Sequence List", ofType: "plist”) {
// use path, which will now be of type String
}
else {
// deal with pathForResource failing
}
You can read more about optionals in introduction of the Swift book.
You haven't translated the entire first line from Objective-C. You are missing the call to NSMutableArray which creates the array from the contents of the file. The original code is confusing because it calls the contents of the file path when it is really questions. Try this:
if let path = NSBundle.mainBundle().pathForResource("Sequence List", ofType: "plist") {
let questions = NSMutableArray(contentsOfFile: path)
//Shuffle the array of questions
numberSequenceList = self.shuffleArray(questions)
currentQuestion = currentQuestion + 1
if Round == 1 {
//Take first object in shuffled array as the first question
let firstQuestion = numberSequenceList[0] as NSArray
//Find question and populate text view
let string = firstQuestion[0] as NSString
self.lblNumber.text = string
//Find and store the answer
let findAnswer = firstQuestion[1] as NSString
Answer = findAnswer.intValue
}
}