Sort class instance alphabetically - iphone

I have this code which works on numbers (distance) which allows me to sort by closest to farthest. However I would like to do something similar but instead sort alphabetically. So I need to sort self.names alphabetically essentially. Also, I'd like to eventually sort self.names alphabetically and if you have identical names then sort those by distance. Is this possible?
- (NSComparisonResult)sortByDistFromVor:(radiostations *)anObject
{
if ([self.distFromVor doubleValue] < [anObject.distFromVor doubleValue]) {
return NSOrderedAscending;
} else if ([self.distFromVor doubleValue] > [anObject.distFromVor doubleValue]) {
return NSOrderedDescending;
}
return NSOrderedSame;
}

String implements a comparison, so the radiostations class (whose name ought to be capitalized by convention) can implement it's name comparison like this:
- (NSComparisonResult)sortByName:(radiostations *)anObject {
return [self.name compare:anObject.name];
}
And to get a secondary sort as you described:
- (NSComparisonResult)sortByNameThenDistance:(radiostations *)anObject {
NSComparisonResult result = [self sortByName:anObject];
return (result == NSOrderedSame)? [self sortByDistFromVor:anObject] : result;
}

Related

Is there a way to sort string lists by numbers inside of the strings?

Is there a way to sort something like:
List<String> hi = ['1hi', '2hi','5hi', '3hi', '4hi'];
to this?
['1hi', '2hi','3hi', '4hi', '5hi']
Just calling List<String>.sort() by itself will do a lexicographic sort. That is, your strings will be sorted in character code order, and '10' will be sorted before '2'. That usually isn't expected.
A lexicographic sort will work if your numbers have leading 0s to ensure that all numbers have the same number of digits. However, if the number of digits is variable, you will need to parse the values of the numbers for sorting. A more general approach is to provide a callback to .sort() to tell it how to determine the relative ordering of two items.
Luckily, package:collection has a compareNatural function that can do this for you:
import 'package:collection/collection.dart';
List<String> hi = ['1hi', '2hi','5hi', '3hi', '4hi'];
hi.sort(compareNatural);
If your situation is a bit more complicated and compareNatural doesn't do what you want, a more general approach is to make the .sort() callback do parsing itself, such as via a regular expression:
/// Returns the integer prefix from a string.
///
/// Returns null if no integer prefix is found.
int parseIntPrefix(String s) {
var re = RegExp(r'(-?[0-9]+).*');
var match = re.firstMatch(s);
if (match == null) {
return null;
}
return int.parse(match.group(1));
}
int compareIntPrefixes(String a, String b) {
var aValue = parseIntPrefix(a);
var bValue = parseIntPrefix(b);
if (aValue != null && bValue != null) {
return aValue - bValue;
}
if (aValue == null && bValue == null) {
// If neither string has an integer prefix, sort the strings lexically.
return a.compareTo(b);
}
// Sort strings with integer prefixes before strings without.
if (aValue == null) {
return 1;
} else {
return -1;
}
}
void main() {
List<String> hi = ['1hi', '2hi','5hi', '3hi', '4hi'];
hi.sort(compareIntPrefixes);
}
You can sort the list like this:
hi.sort();
(because numbers sort before letters in its implementation)

How to Compare Two NSStrings which contain float values? [duplicate]

This question already has answers here:
Compare version numbers in Objective-C
(15 answers)
Closed 9 years ago.
I have two strings, one contains the value "5.2.3" and another one contain a value like "5.2.32". My question is: how to compare these two strings?
if ([string1 integerValue] >= [sting2 integerValue])
{
NSLog(#"process");
}
I tried above line but not got it.
Well correct answer has been already given. Because I have spent my half an hour on it so I don't want to waste it.
-(BOOL)string:(NSString*)str1 isGreaterThanString:(NSString*)str2
{
NSArray *a1 = [str1 componentsSeparatedByString:#"."];
NSArray *a2 = [str2 componentsSeparatedByString:#"."];
NSInteger totalCount = ([a1 count] < [a2 count]) ? [a1 count] : [a2 count];
NSInteger checkCount = 0;
while (checkCount < totalCount)
{
if([a1[checkCount] integerValue] < [a2[checkCount] integerValue])
{
return NO;
}
else if([a1[checkCount] integerValue] > [a2[checkCount] integerValue])
{
return YES;
}
else
{
checkCount++;
}
}
return NO;
}
And you can call this method like this:-
if([self string:str1 isGreaterThanString:str2])
{
NSLog(#"str2 is lower than the str1");
}
else
{
NSLog(#"str1 is lower than the str2");
}
It would appear that what you have here are not really "float" values, but some kind of multi-part "number" (akin to software version numbering?) that is not going to be covered by any of the standard conversions, but will also not compare "correctly" as just simple strings.
First you need to specify exactly what your comparison rules are. For example, I suspect you want something like:
1.2 > 1.1
1.1.1 > 1.1
1.11 > 1.2
1.2.3 > 1.2.2
1.2.22 > 1.2.3
(in other words, split the string up by "."s, and do a numeric comparison on each component). You'll have to decide how you want to handle things like letters, other delimiters, etc. showing up in the input. For example is 1.0b1 > 1.01 ?
Once you settle on the rules, write a method (returning NSComparisonResult) to implement the comparison. If you want to get fancy, you can even define your comparison method in a category on NSString, so you could do things like
if ([string1 mySuperDuperCompareTo:string2] == NSOrderedAscending) {
NSLog(#"%# < %#", string1, string2);
} // ... etc ...
see also How to let the sortedArrayUsingSelector using integer to sort instead of String?
#The Tiger is correct. Sorry to misunderstood your question. I have already mark deleted as my older answer. Here is the updated one.
As there are multiple . (dots) available here is the new solution. This will check value first like 5.2.3 and 5.2.32 are there. Then,
check first value 5 - same
so check next 2 - same
check next 3 and 32 - 32 is larger
also check for the same string as well (Also one of the probability)
Here is the logic - I have not compiled but this is base idea - there might require some correction
// separate from "."
NSArray *arrString1 = [string1 componentSeparatedBy:#"."];
NSArray *arrString2 = [string1 componentSeparatedBy:#"."];
BOOL isString1Bigger = NO; // a variable to check
BOOL isString2Bigger = NO; // a variable to check
// check count to run loop accordingly
if ([arrString1 count] <= [arrString2 count]) {
for (int strVal=0; strVal<[arrString1 count]; strVal++) {
// compare strings value converted into integer format
// when you get larger then break the loop
if([[arrString1 objectAtIndex:strVal] intValue] > [[arrString2 objectAtIndex:strVal] intValue]) {
isString1Bigger = YES;
break;
}
}
if ([arrString1 count] > [arrString2 count]) {
// use arrString2 in loop and isString2Bigger as a mark
}
// if after running both the if condition still require to check if both are same or not, for that,
if ((isString1Bigger == NO) && (isString2Bigger == NO)) {
// same string values
}
There might some modification required to run over. But its the base concept to compare string value provided by you.

Why Does String Not Equal What Is Stored?

This is a simple, odd question...
if(tableViewNum == #"One") {
if ([drinkArray objectAtIndex:0] == currentDate) {
[updatedArray addObject:drinkArray];
NSLog(#"MADE THE ELSE1");
}
NSLog(#"MADE THE ELSE2");
}
else if (tableViewNum == #"Two") {
if ([[drinkArray objectAtIndex:0] isEqualToString:yesterdayDate])
[updatedArray addObject:drinkArray];
} else {
NSLog(#"MADE THE ELSE %#",tableViewNum);
[updatedArray addObject:drinkArray];
}
In the very first if statement I ask if tableViewNum == #"One"
But I don't go in that section of the if statement even though tableViewNum actually does equal #"One"
As you can see the very last NSLog all ways comes out as
MADE THE ELSE One
But if tableViewNum really equaled One it would have gone through the if statement not the else statement code...?????
You can't compare strings with the == operator. Use isEqualToString instead:
if([tableViewNum isEqualToString:#"One"]) {
// etc.
… and the same for the rest of the conditions. You're already doing it right in the second block.
To be more specific, you shouldn't compare ANY objects using ==. This compares just the pointers. Use [obj isEqual: otherObj] or with NSStrings isEqualToString: as described above.

Get index of object in array to look up corresponding object in other array

I have two arrays. One is an array of names and the other is an array made up of strings titled "Yes" or "No". The index path of each name in the "name" array corresponds with the same index path in the "Yes/No" array. For example:
Names Array | Yes/No Array
Person 1 | Yes
Person 2 | No
Person 3 | Yes
What would be the easiest way to look up a person's name (possibly getting the index path of it) and check whether they are "Yes" or "No" in the "Yes/No" array?
Also, I'm not sure if "index path" is the right term to use. If it isn't, I mean the number that an object is in an array.
NSArray has a method called indexOfObject that will return either the lowest index whose corresponding array value is equal to anObject or NSNotFound if no such object is found. If your array of names is unsorted, then use this to get the index that you can then plug in to the Yes/No array. That is, something along these lines:
NSString *answer = nil;
NSUInteger index = [namesArray indexOfObject:#"John Smith"];
if (index != NSNotFound) {
answer = [yesNoArray objectAtIndex:index];
}
return answer;
Because Bavarious asks questions where I assume, here's a better way when the array of names is sorted alphabetically.
int index = [self findName:#"John Smith"];
NSString *answer = nil;
if (index >= 0) {
answer = [yesNoArray objectAtIndex:index];
}
return answer;
where the function findName is a simple binary search:
-(int)findName:(NSString *)name {
int min, mid, max;
NSComparisonResult comparisonResult;
min = 0;
max = [namesArray count]-1;
while (min <= max) {
mid = min + (max-min)/2;
comparisonResult = [name compare:[namesArray objectAtIndex:mid]];
if (comparisonResult == NSOrderedSame) {
return mid;
} else if (comparisonResult == NSOrderedDescending) {
min = mid+1;
} else {
max = mid-1;
}
}
return -1;
}
Trying to keep two arrays synchronized is just asking for trouble. It can be done, of course, but whenever you modify one array, you have to remember to make a corresponding change to the other. Do yourself a favor and avoid that entire class of bugs by rethinking the way you're storing data.
In this case, you've got a {person, boolean} pair. One option is to store each pair as a dictionary, and then keep an array of those dictionaries. This would be a particularly good plan if you might expand the number of pieces of data beyond the two that you have. Another option would be to just use a dictionary where keys are person names and the values are your yes/no values. This makes the answer to your question very simple:
NSString *yesOrNo = [personDictionary objectForKey:personName];
Getting back to your original question, where you still have the two arrays, the easiest thing to do is to iterate over the person array until you find the person you're looking for, get the index of that name, and then look up the corresponding value in the yes/no array:
for (person in peopleArray) {
if ([person isEqualToString:thePersonYoureLookingFor]) {
yesNoValue = [yesNoArray objectAtIndex:[peopleArray indexOfObject:person];
break;
}
}
That's fine if the number of people in the list isn't too large. If the list could be large, then you'll want to keep the person array sorted so that you can do a binary search. The trouble there, though, is that you're yes/no array is separate, so sorting the personArray while keeping the yes/no array in the right order becomes complicated.
You can also use below of the code, May its useful to you,
NSSortDescriptor *_lastDescriptor = [[NSSortDescriptor alloc] initWithKey:#"" ascending:YES];
NSArray *_lastArray = [NSArray arrayWithObject:_lastDescriptor];
firstCharacterArray = (NSMutableArray *)[[nameIndexesDictionary allKeys]
sortedArrayUsingDescriptors:_lastArray];
//firstCharacterArray = (NSMutableArray *)[[nameIndexesDictionary allKeys]
sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
for (NSString *eachlastIndex in firstCharacterArray)
{
NSSortDescriptor *lastDescriptor = [[NSSortDescriptor alloc] initWithKey:#""
ascending:YES];
//selector:#selector(localizedCaseInsensitiveCompare:)] ;
NSArray *descriptorslast = [NSArray arrayWithObject:lastDescriptor];
[[nameIndexesDictionary objectForKey:eachlastIndex]
sortUsingDescriptors:descriptorslast];
[lastDescriptor release];
}
You can use indexOfObject method to get the index of element.
for example
This will give you index of your object
NSInteger index = [yourArray indexOfObject:objectName];
To see the corresponding element from another array
[anotherArray objectAtIndex:index];
This worked for me. Hope this helps.

How to compare self.title to a string in Objective C?

What am I doing wrong in the below code? My if statement is missing something:
if ([self.title] = "Upcoming Events") {
} else {
}
Correct would be:
if( [self.title isEqualToString:#"Upcoming Events"] )
self.title is a pointer, you can only compare it to other pointers using == not their values.
if ([self.title isEqualToString:#"Upcoming Events"]) {
NSLog(#"True");
} else {
NSLog(#"False");
}
You just have to write like this:
if([self.title isEqualToString:#"Upcoming Events"])
{
}
else
{
}
also .... in a if you should use "==" instead of "=". When there is "==" it is checking if they are equal while if there is "=" it gives the first one the value of the second.