Sorting array not working properly? - iphone

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.

Related

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.

Counting PList keys at a specific level

I'm trying to create a grouped tableview, but when it comes to the number rows in sections I haven't been able to get the correct values. From the list below 'OrdreLinje', 'OrdreStatus' and 'KundeLeveranse' are the sections and the items below would be the rows visible to the user. So the number of rows in the sections would be 4,1,1 respectively, my question is how do I count these keys to produce the correct result.
Root(Dict)
-->Rows(Array)
---->Item 0(Dict)
------>OrdreLinje(Array)
-------->item0(Dict)
-------->item1(Dict)
-------->item2(Dict)
-------->item3(Dict)
------>KundeLeveranse(Array)
-------->item0(Dict)
------>OrdreStatus(Array)
-------->item0(Dict)
Sorry, I did try to insert an image but i'm not reputable enough :)
Any help is greatly appreciated,
B
Are you wanting a count of the keys in the first dictionary in the Rows array, or the sum of the keys in all the dictionaries in the Rows array?
For the first, you could do:
NSArray *rows = [rootDict objectForKey:#"Rows"];
NSInteger count = 0;
if (rows.count > 0)
{
NSDictionary *firstRow = [rows objectAtIndex:0];
count = firstRow.allKeys.count;
}
If you want the count of all keys in all dictionaries in the Rows array, you could do:
NSArray *rows = [rootDict objectForKey:#"Rows"];
NSInteger count = 0;
for (NSDictionary *dict in rows)
{
count += dict.allKeys.count;
}

How to turn NSString to a number

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!

Sorting nsarray by index

I simply want to sort an NSArray by the index number i.e. The order in which the values are entered into the array.
My problem is that I use this array in a uipicker, and therefore when reusing labels, end up with my values in the wrong order
My values consist of fractions. 1/4,3/8,1/2,3/4,1,1-1/14,1-3/8 etc
I want these fractions to display in the order they are entered
Must be simple, but I am having no luck
When I use sorted array localisedstandardcompare all the values get out of sequence
Any help will be appreciated
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
// Only calls the following code if component "0" has changed.
if (component == 0)
{
// Sets the global integer "component0Row" to the currently selected row of component "0"
component0Row = row;
// Loads the new values for the selector into a new array in order to reload the data.
NSDictionary *newDict = [[NSDictionary alloc]initWithDictionary:[pickerData objectForKey:[selectorKeysLetters objectAtIndex:component0Row]]];
NSArray *sortArray = [[NSArray alloc]initWithArray:[newDict allKeys]];
NSMutableArray *newValues = [[NSMutableArray alloc]initWithArray:[sortArray sortedArrayUsingSelector:#selector(compare:)]];
self.selectorKeysNumbers = newValues;
component1Row = 0;
[self.myPicker selectRow:0 inComponent:1 animated:NO];
Your array is already sorted by the index number
Assuming that the array values are NSStrings the sort order will be by string value, not numeric value. In order to sort these fractions (rational numbers) you would have to write you own compare function.
But see #hypercrypt, the array should already be in the order entries were made.

Getting Index of an Object from NSArray?

i am trying to get index of an array through indexOfObject method as follows but when i try to log the value to test the index i get a garbage value.. for testing purposes i am having an array with values {57,56,58..} to get an index of lets say 56,
NSNumber *num = [NSNumber numberWithInteger:56];
NSInteger Aindex = [myArray indexOfObject:num];
NSLog(#" %d",Aindex);
the value i get is something like 2323421. what am i possibly doing wrong??
The index returned by indexOfObject will be the first index for an occurence of your object. Equality is tested using isEqual method.
The garbage value you get is probably equal to NSNotFound.
Try testing anIndex against it. The number you are looking for isn't probably in your array :
NSNumber *num=[NSNumber numberWithInteger:56];
NSInteger anIndex=[myArray indexOfObject:num];
if(NSNotFound == anIndex) {
NSLog(#"not found");
}
or log the content of the array to be sure :
NSLog(#"%#", myArray);
Folks,
When an object is not found in the array the indexOfObject method does NOT return a 'garbage' value. Many systems return an index of -1 if the item is not found.
However, on IOS - because the indexOfObject returns an UNSIGNED int (aka NSUInteger) the returned index must be greater than or equal to zero. Since 'zero' is a valid index there is no way to indicate to the caller that the object was not found -- except by returning an agreed upon constant value that we all can test upon. This constant agreed upon value is called NSNotFound.
The method:
- (NSUInteger)indexOfObject:(id)anObject;
will return NSNotFound if the object was not in the array. NSNotFound is a very large POSITIVE integer (usually 1 minus the maximum int on the platform).
NSNumber *num1 = [NSNumber numberWithInt:56];
NSNumber *num2 = [NSNumber numberWithInt:57];
NSNumber *num3 = [NSNumber numberWithInt:58];
NSMutableArray *myArray = [NSMutableArray arrayWithObjects:num1,num2,num3,nil];
NSNumber *num=[NSNumber numberWithInteger:58];
NSInteger Aindex=[myArray indexOfObject:num];
NSLog(#" %d",Aindex);
Its giving the correct output, may be u have done something wrong with storing objects in ur array.
Try this:
NSArray's indexOfObject: method. Such as the following:
NSUInteger fooIndex = [someArray indexOfObject: someObject];
If you're using Swift and optionals make sure they are unwrapped. You cannot search the index of objects that are optionals.
I just checked. Its working fine for me. Check if your array has the particular number. It will return such garbage values if element is not present.
indexOfObject methord will get the index of the corresponding string in that array if the string is like #"Test" and you find like #"TEST" Now this will retun an index like a long number