How to turn NSString to a number - iphone

I need to sort a list of files according to the number after "_" :
"filename_1" "filename_2" ......
I know that I can extract the number, then sort the filename with the number, but I have to consider what if some illegal name exist and the program turn to be long.
What I want to do is just simply compare the whole String, the same char must has the same number. But when I do [#"word" intValue], the result is zero if the String is not a number. I want to know is there a good way to turn a String into a number.

Take a look at NSString's method:
- (NSComparisonResult)compare:(NSString *)aString options:(NSStringCompareOptions)mask
and the NSNumericSearch option.

If you wish to sort them on your own then you will need to use the
- (NSComparisonResult)compare:(NSString *)aString;
routine.
Here is the reference to the NSComparisonResult capable outputs.
These constants are used to indicate how items in a request are ordered.
enum {
NSOrderedAscending = -1,
NSOrderedSame,
NSOrderedDescending
};
typedef NSInteger NSComparisonResult;
Constants:
NSOrderedAscending
The left operand is smaller than the right operand.
NSOrderedSame
The two operands are equal.
NSOrderedDescending
The left operand is greater than the right operand.
If you think it easier, your can fill an NSArray with your separated strings, then use something like the following:
sortedArray = [anArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
Link to a good QA from SO:
How to sort a NSArray alphabetically?
There is 1 final way I can think of in your case. That would be to use the hasPrefix method of NSString to make sure that each of your strings begins with "filename_" as a first validation. afterwards substring the overall string just getting the remaining string after the "filename_". If all of your filenames are to have a number of 1 or greater, then a 0 means the string is invalid at this point, else the intValue should return a valid positive integer, and you can sort via the integer values.

This should work:
NSString *good = #"filename_1";
NSString *bad = #"filename";
NSCharacterSet *letterSet= [NSCharacterSet letterCharacterSet];
good = [good stringyByTrimmingCharactersInSet:letterSet]; // 1
bad = [bad stringByTrimmingCharactersInSet:letterSet]; // <empty>

You can use following coe to sort the array containing the list of File Objects:
NSSortDescriptor *aSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"fileName" ascending:YES];
[arrayOfFileNames sortUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]];
Hope this is helpful to you...

I think you can not compare it with NSString because NSString follows 1,10,11,12,13,14 .....2,20,21,22 ......this type of ascending order while integer follows like 0,1,2,3,4,5,6,7....... and so on..... So you have to split the last character from string then will have to compare.
well how to short string in ascending order ....
NSMutableArray *array = [NSMutableArray arrayWithObjects:#"f_1",#"f_2",#"f_12",#"f_6",#"f_9",#"f_4", nil];
NSSortDescriptor *name = [[[NSSortDescriptor alloc] initWithKey:#"" ascending:YES] init];
[array sortUsingDescriptors:[NSMutableArray arrayWithObjects:name, nil]];
but this will give you string shorting not according to number.
Thank You!

Related

NSExpression Dividing Lower Number By Higher Number [duplicate]

I am making a calculator that logs input in a label named "inputLabel' and then outputs the answer in a different label named "outputLabel" (similar to a graphing calculator). Once the user is finished entering the expression, the expression is stored in an NSString object and then parsed with the NSPredicate class and evaluated with the NSExpression class. What I have works, but I have noticed for particular operations the answers are not correct. For example, if the user types in "25/2" the calculator returns 12, which is obviously incorrect. However, if the user types in "25/2.0" or "25.0/2" the calculator returns 12.5 which is what I want. It seems that the NSExpression method 'expressionValueWithObject' is interpreting the operands as integers instead of floats. If this is the case, is there a way that I change the 'expressionValueWithObject'method to interpret the operands as floats?
Brain.m
-(float)performCalculation: (NSString *)operation
{
NSPredicate *parsed = [NSPredicate predicateWithFormat:[operation stringByAppendingString:#"=1.0"]];
NSExpression *inputExpressionParsed = [(NSComparisonPredicate *)parsed leftExpression];
NSNumber *result = [inputExpressionParsed expressionValueWithObject:inputExpressionParsed context:nil];
return [result floatValue];
}
ViewController.m
- (IBAction)equalsPressed:(id)sender
{
//self.inputLabel.text = [self.inputLabel.text stringByAppendingString:#".0"];
NSString *inputExpression = self.inputLabel.text;
self.inputLabel.text = [self.inputLabel.text stringByAppendingString:#"="];
float result = [self.brain performCalculation:inputExpression];
self.outputLabel.text = [NSString stringWithFormat:#"%g", result];
}
No, NSExpression cannot do that. You could try to append ".0" to all integer numbers
in the string before evaluating it, but the better solution is probably to use a "proper"
math expression parser, for example
https://github.com/davedelong/DDMathParser
You could iterate through the expression tree replacing the expression with the integer value (expressionType == NSConstantExpression). It depends a little bit of the features of your calculator, whether it is worth or not.

Sorting array not working properly?

I am sorting a array of string numbers using ios inbuilt sorting method but it is giving me wrong output.So I applied bubble sorting for a while,Any body can explaing why it is behaving like that.So that I can optimize my code.
NSArray *numbers=#[#"45",#"2",#"11",#"31",#"240",#"310"];
numbers=[numbers sortedArrayUsingSelector:#selector(compare:)];
NSLog(#"sorted array is %#",numbers);
NSMutableArray *m_Array=[[NSMutableArray alloc] initWithArray:numbers];
[numbers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
for (int j=idx+1; j<numbers.count; j++) {
if ([m_Array[idx] intValue]>[m_Array[j] intValue]) {
NSString *temp=m_Array[idx];
[m_Array replaceObjectAtIndex:idx withObject:m_Array[j]];
[m_Array replaceObjectAtIndex:j withObject:temp];
}
}
}];
NSLog(#"sorted array after bubble sort is %#",m_Array);
output is
sorted array is (
11,
2,
240,
31,
310,
45
)
sorted array after bubble sort is (
2,
11,
31,
45,
240,
310
)
That's because you are comparing string objects, not numbers.
Try changing your array to be numbers and not strings (which are in quotes).
In other words, instead of
NSArray *numbers=#[#"45",#"2",#"11",#"31",#"240",#"310"];
you do:
NSArray *numbers=#{#45,#2,#11,#31,#240,#310};
(which are Objective-C literals, as described in this documentation), you'll see much better results.
The reason the "bubble sort" method is working better for you is because you get the "intValue" of your string objects in that array. That's not happening for the first algorithm.
Use NSNumber rather than using string for adding integer values to an array.
NSMutableArray *array =[NSMutableArray alloc]initWithObjects:[NSNumber numberWithInteger:12],[[NSNumber numberWithInteger:122] ];
And then sort
[array sortedArrayUsingSelector:#selector(compare:)]
This is because sorting in Objective-C sorts data with by first element and if the first element is same then it looks for the next one otherwise it sorts on the basis of first element value.suppose case of 11 and 2 , as it checks for first element and first element of 2 is greater than first element of 11 (i.e; 1).So it will declare 2 as greater for sorting purpose.And 2 will come after 11.
For sorting you have to keep prefix values of numbers in order to sort properly.For example: 001,002,003 for 3 digits no and 01,02,03 for two digit no.
NSMutableArray *tempArray=[[NSMutableArray alloc] initWithCapacity:[numbers count]];
[numbers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[tempArray addObject:[NSString stringWithFormat:#"%03d",[numbers[idx] intValue]]];
}];
NSLog(#"sorted array is %#",[tempArray sortedArrayUsingSelector:#selector(compare:)]);
Note:---Only for variable digit size,--- count maximum no in array and count its digits programmically and set string format accordingly.

Sorting of NSMutableDictionary

Confusing !!!
I have one NSMutableDictionary called tempDict, having keys Freight, Fuel , Discount (and many more) with relevant values.
I am generating two different NSMutableArrays called arrTVBuyCharge and arrTVBuyCost from tempDict using this Code :
[arrTVBuyCharge addObjectsFromArray:[(NSArray *)[tempDict allKeys]]];
[arrTVBuyCost addObjectsFromArray:[(NSArray *)[tempDict allValues]]];
Problem : I want Freight, Fuel and Discount at the Top in the above arrays in same order (Ofcourse , with Ordering of Values).
What is the Optimum way to achieve this ?
It seems tricky at first, but it's simple when you think about it. All you want to do is get a sorted list of keys, and look up the value for each key as you add them to your arrays.
To get an array with the list of sorted keys:
NSArray *sortedKeys = [[tempDict allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
Then iterate through those and add them to NSMutableArrays:
NSMutableArray *arrTVBuyCharge = [[NSMutableArray alloc] init];
NSMutableArray *arrTVBuyCost = [[NSMutableArray alloc] init];
for (NSString *key in sortedKeys) {
[arrTVBuyCharge addObject:key];
[arrTVBuyCost addObject:[tempDict objectForKey:key]];
}
For even better performance, use the initWithCapacity method for the NSMutableArrays since you know the size.
This is the standard way of doing it.
1) Get three objects separately :
NSArray *mainKeys = #[#"Freight", #"Fuel", #"Discount"];
NSArray *mainValues = #[[tempDict valueForKey:#"Freight"],
[tempDict valueForKey:#"Fuel"],
[tempDict valueForKey:#"Discount"]
];
[arrTVBuyCharge addObjectsFromArray:mainKeys];
[arrTVBuyCost addObjectsFromArray:mainValues];
2) Remove them from tempDict :
[tempDict removeObjectsForKeys:mainKeys];
3) Add the objects from Updated tempDict :
[arrTVBuyCharge addObjectsFromArray:(NSArray *)[tempDict allKeys]];
[arrTVBuyCost addObjectsFromArray:(NSArray *)[tempDict allValues]];
This will make Freight, Fuel and Discount to be at index 0, 1 and 2 in your new Arrays.
Man, NSMutableDictionary always returns keys in a disordered fashion, if you really want to maintain order then you can sort it in alphabetical order or you can add 01, 02 ,03 serial numbers before your values to sort them in the order they were put it, later trim the first two characters of the string and use it.

iOS iPhone how to list all keywords in a UTextView by frequency of use?

I got a UITextView with an arbitrary length text (up to 10000 characters). I need to parse this text, extract all keywords and list them by the frequency of use with the most frequently used word being on top, next one down, etc. I will most likely present a modal UITableView after the operation is completed.
I'm thinking of an efficient and useful way to do this. I can try to separate a string using a delimiter in the form of [whitespace, punctuation marks, etc].
This gets me an array of character sequences.
I can add each add sequence as an NSMutableDictionary key, and increment its count once I see another instance of that word. However, this may result in a list of 300-400 words, most having frequency of 1.
Is there a good way to implement the logic that I'm describing? Should I try to sort the array in alphabetical order and try some kind of "fuzzy" logic match? Are there any NSDataDetector or NSString methods that can do this kind of work for me?
An additional question is: how would I extract stuff like a, at, to, for, etc, and do not list them in my keyword list?
It would be great if I can take a look at a sample project that has already accomplished this task.
Thank you!
You can use CFStringTokenizer to get the word boundaries. For counting, you could use an NSMutableDictionary, as you suggested, or an NSCountedSet, which might be slightly more efficient.
If you're not interested in words that have a frequency of 1 (or some other threshold), you would have to filter them out after counting all the words.
For ignoring certain words (a, the, for...), you need a word list specific to the language of your text. The Wikipedia article on stop words contains a couple of links, e.g. this CSV file.
There are many approaches to do this.
You should definitely add all your Keywords to an array (or other collection object) and reference it/ iterate through it so you are searching for these keywords and only these keywords (and are avoiding checking for occurrences of a, at, to, for, etc.)
NSArray *keywords = [ add your keywords ];
NSString *textToSearchThrough = #" your text "; // or load your text File here
- loop control statement here (like maybe fast enumerate), and inside this loop:
NSRange range = [textToCheckThrough rangeOfString:keywords[currentKeyword]
options:NSCaseInsensitiveSearch];
if(range.location != NSNotFound) {
// meaning, you did find it
// add it to a resultsArray, add 1 to this keyword's occurrenceCounter (which you must also declare and keep track of)
// etc.
}
Then you loop through your results array, check number of occurrences per keyword, purge those who's occurrence count is < minOccurrenceCount, and sort remaining from highest to lowest.
I ended up going with the CFStringTokenizer . I'm not sure if the bridged casts below are correct, but it seems to work
-(void)listAllKeywordsInString:(NSString*)text
{
if(text!=nil)
{
NSMutableDictionary* keywordsDictionary = [[NSMutableDictionary alloc] initWithCapacity:1024];
NSString* key = nil;
NSLog(#"%#",text);
NSLog(#"Started parsing: %#",[[NSDate date] description]);
CFStringRef string =(__bridge CFStringRef)text; // Get string from somewhere
CFStringTokenizerRef tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, (__bridge_retained CFStringRef) text, CFRangeMake (0,CFStringGetLength((__bridge_retained CFStringRef)text)), kCFStringTokenizerUnitWord, CFLocaleCopyCurrent());
unsigned tokensFound = 0; // or the desired number of tokens
CFStringTokenizerTokenType tokenType = kCFStringTokenizerTokenNone;
while(kCFStringTokenizerTokenNone != (tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer)) ) {
CFRange tokenRange = CFStringTokenizerGetCurrentTokenRange(tokenizer);
CFStringRef tokenValue = CFStringCreateWithSubstring(kCFAllocatorDefault, string, tokenRange);
// This is the found word
key =(__bridge NSString*)tokenValue;
//increment its count
NSNumber* count = [keywordsDictionary objectForKey:key];
if(count!=nil)
{
[keywordsDictionary setValue:[NSNumber numberWithInt:1] forKey:key];
}else {
[keywordsDictionary setValue:[NSNumber numberWithInt:count.intValue+1] forKey:key];
}
CFRelease(tokenValue);
++tokensFound;
}
NSLog(#"Ended parsing. tokens Found: %d, %#",tokensFound,[[NSDate date] description]);
NSLog(#"%#",[keywordsDictionary description]);
// Clean up
CFRelease(tokenizer);
}
}

Comparing Strings in Objective-C

I'm writing a small app for the iphone and I'm trying to write a function that will insert an NSMutableString into an NSArray in alphabetical order. Also I'll be writing a sort to sort the entire array as well. For both cases I'm wondering what the best way of comparing NSMutableStrings is. Is there a specific function I can use?
Thanks for your help.
I think you're looking for
(NSComparisonResult)[aString compare: bString];
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/nsstring_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/compare:
You can use this or one of the related methods if you're doing insertion sort. However, if you want to do a one time sort of the NSMutableArray, you can use one of the NSMutableArray sorting methods such as sortUsingComparator:.
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html#//apple_ref/occ/instm/NSMutableArray/sortUsingComparator:
If you look under "Identifying and comparing strings" in the NSString reference, you'll find several options. They do slightly different things, since you might want to compare strings in different ways (e.g. are numbers compared in lexical or numeric order?). The most basic is compare: — you can probably start there and choose a more complicated version as needed.
I think this should work for you. This is my answer which I have taken from the link:
Comparing text in UITextView?
SOLUTION-1: I have modified it here a bit to make it more easier for your case:
Let us assume String1 is one NSString.
//Though this is a case sensitive comparison of string
BOOL boolVal = [String1 isEqualToString:#"My Default Text"];
//Here is how you can do case insensitive comparison of string:
NSComparisonResult boolVal = [String1 compare:#"My Default Text" options:NSCaseInsensitiveSearch];
if(boolVal == NSOrderedSame)
{
NSLog(#"Strings are same");
}
else
{
NSLog(#"Strings are Different");
}
Here if boolVal is NSOrderedSame then you can say that strings are same else they are different.
SOLUTION-2: Also you don't find this easy, you can refer to Macmade's answer under the same link.
Hope this helps you.
For sorting array
NSArray *sortedArray = [anArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
try BOOL ans = [str1 isEqualToString:str2];
Try NSArray's sortedArrayUsingSelector: method:
NSArray * stringArray = [NSArray arrayWithObjects:#"dddsss", #"aada", #"bbb", nil];
[stringArray sortedArrayUsingSelector:#selector(compare:)];
NSLog(#"%#", [stringArray sortedArrayUsingSelector:#selector(compare:)]);
Out put:
(
aada,
bbb,
dddsss
)
What's more, you can use NSSortDescriptor to decide ASC or DESC order.