This question already has answers here:
How do I sort an NSMutableArray with custom objects in it?
(27 answers)
Sorting two NSArrays together side by side
(4 answers)
Closed 9 years ago.
I have 2 NSMutableArrays. First array contains custom object intances with property NSString *itemID, second array contains only from NSString objects with same values of itemID, but in another order. I need to sort first array by itemID property of each object, and it should be sorted like second array.
How I can do this?
guideArray = < YOUR SECOND ARRAY WITH STRING OBJECT >;
unsortedArray = < YOUR FIRST ARRAY WITH CUSTOM OBJECT >;
[unsortedArray sortUsingComparator:^(id o1, id o2) {
Items *item1 = o1;
Items *item2 = o2;
NSInteger idx1 = [guideArray indexOfObject:item1.ItemID];
NSInteger idx2 = [guideArray indexOfObject:item2.ItemID];
return idx1 - idx2;
}];
NSLog(#"%#",unsortedArray);
Store the custom objects in an dictionary with itemID as key, use this dictionary as lookup to sort the objects:
NSArray *objects; // your objects
NSMutableArray *hintArray; // your sorted IDs
NSMutableDictionary *lookupDict = [[NSMutableDictionary alloc] initWithCapacity:[objects count]];
NSMutableArray *sortedObjects = [[NSMutableArray alloc] initWithCapacity:[hintArray count]];
for (id object in objects) {
[lookupDict setValue:object forKey:[object itemID]];
}
for (id hint in hintArray) {
[sortedObjects addObject:[lookupDict valueForKey:hint]];
}
EDIT:
Solution with inplace sort of objects:
NSMutableArray *objects;
NSMutableArray *hintArray;
NSMutableDictionary *lookupDict = [[NSMutableDictionary alloc] initWithCapacity:[hintArray count]];
int i = 0;
for (NSString *itemID in hintArray) {
[lookupDict setValue:[NSNumber numberWithInt:i] forKey:itemID];
i++;
}
[objects sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [[lookupDict valueForKey:[obj1 itemID]] compare:[lookupDict valueForKey:[obj2 itemID]]];
}];
You can compare your two objects using following syntax :-
[items sortUsingComparator:^NSComparisonResult(Attribute *obj1, Attribute *obj2)
{
return [[NSNumber numberWithInt:[stringOrder indexOfObject:obj1.itemID]] compare:[NSNumber numberWithInt:[stringOrder indexOfObject:obj2.itemID]]]
}];
or else you can use following snippet :
NSArray* sortedKeys = [dict keysSortedByValueUsingComparator:^(id obj1, id obj2)
{
return [obj1 compareTo:obj2];
}
Enjoy Programming !
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Generating permutations of NSArray elements
Let's say that I have
[1,2]
And I want to get
{1}
{2}
{1, 2}
{2, 3}
I think the name of the thing you're looking for is 'power set'. It sounded fun, so here's a crack at it. I relied on this very concise article for the algorithm. I'm not sure if this is efficient (...actually, I'm sure this is inefficient) over large sets.
// answer the powerset of array: an array of all possible subarrays of the passed array
- (NSArray *)powerSet:(NSArray *)array {
NSInteger length = array.count;
if (length == 0) return [NSArray arrayWithObject:[NSArray array]];
// get an object from the array and the array without that object
id lastObject = [array lastObject];
NSArray *arrayLessOne = [array subarrayWithRange:NSMakeRange(0,length-1)];
// compute the powerset of the array without that object
// recursion makes me happy
NSArray *powerSetLessOne = [self powerSet:arrayLessOne];
// powerset is the union of the powerSetLessOne and powerSetLessOne where
// each element is unioned with the removed element
NSMutableArray *powerset = [NSMutableArray arrayWithArray:powerSetLessOne];
// add the removed object to every element of the recursive power set
for (NSArray *lessOneElement in powerSetLessOne) {
[powerset addObject:[lessOneElement arrayByAddingObject:lastObject]];
}
return [NSArray arrayWithArray:powerset];
}
If you think this is a keeper, you could make it a category method on array and drop the parameter. Test it like this...
NSLog(#"empty = %#", [self powerSet:[NSArray array]]);
NSLog(#"one item = %#", [self powerSet:[NSArray arrayWithObject:#"a"]]);
NSLog(#"two items = %#", [self powerSet:[NSArray arrayWithObjects:#"a", #"b", nil]]);
NSLog(#"three items = %#", [self powerSet:[NSArray arrayWithObjects:#"a", #"b", #"c", nil]]);
I did only these tests, and the output looked good. Spoiler alert: the three item test looks roughly like this on my console (with \n's removed):
three items = ((),
(a),
(b),
(a,b),
(c),
(a,c),
(b,c),
(a,b,c))
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
How to sort array having numbers as string in iPhone?
How Do I sort an NSMutable Array with NSNumbers in it?
I have a NSMutableArray with random order of numbers. I have to sort them in ascending and descending order? Is there any in built function for that and if no how it can be done. Array is like this:
arr = ["12","85","65","73","21","87","1","34","32"];
Sorting NSMutableArray (based on key) which contains objects
First, you’ll need to create an NSSortDescriptor and tell it which key to sort the array on.
NSSortDescriptor *lastNameSorter = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:YES];
[personList sortUsingDescriptors:[NSArray arrayWithObject:lastNameSorter]];
Hope this Full tutorial helps you.
use sortUsingSelector instance method of class NSMutableArray.
use this line (But you need to use NSNumbers rather than string in case of numbers)
[myArray sortUsingSelector:#selector(compare:)];
It sort array in ascending order. for descending order add this line after above line.
myArray=[myArray reverseObjectEnumerator] allObjects];
example code for your case:
NSArray *sortedArray;
sortedArray = [anArray sortedArrayUsingFunction:intSort context:NULL];
NSInteger intSort(id num1, id num2, void *context)
{
int v1 = [num1 intValue];
int v2 = [num2 intValue];
if (v1 < v2)
return NSOrderedAscending;
else if (v1 > v2)
return NSOrderedDescending;
else
return NSOrderedSame;
}
you can develop a logic to sort your array in intsort method and pass it as parameter to above method.
there are many predefined methods like:
sortUsingDescriptors:
sortUsingComparator:
sortWithOptions:usingComparator:
sortUsingFunction:context:
sortUsingSelector:
follow developer.apple.com for api
good luck TNX
Given an NSArray of NSDictionary objects (containing similar objects and keys) is it possible to write perform a map to an array of specified key? For example, in Ruby it can be done with:
array.map(&:name)
It only saves a couple lines, but I use a category on NSArray. You need to ensure your block never returns nil, but other than that it's a time saver for cases where -[NSArray valueForKey:] won't work.
#interface NSArray (Map)
- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block;
#end
#implementation NSArray (Map)
- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block {
NSMutableArray *result = [NSMutableArray arrayWithCapacity:[self count]];
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[result addObject:block(obj, idx)];
}];
return result;
}
#end
Usage is much like -[NSArray enumerateObjectsWithBlock:]:
NSArray *people = #[
#{ #"name": #"Bob", #"city": #"Boston" },
#{ #"name": #"Rob", #"city": #"Cambridge" },
#{ #"name": #"Robert", #"city": #"Somerville" }
];
// per the original question
NSArray *names = [people mapObjectsUsingBlock:^(id obj, NSUInteger idx) {
return obj[#"name"];
}];
// (Bob, Rob, Robert)
// you can do just about anything in a block
NSArray *fancyNames = [people mapObjectsUsingBlock:^(id obj, NSUInteger idx) {
return [NSString stringWithFormat:#"%# of %#", obj[#"name"], obj[#"city"]];
}];
// (Bob of Boston, Rob of Cambridge, Robert of Somerville)
I've no idea what that bit of Ruby does but I think you are looking for NSArray's implementation of -valueForKey:. This sends -valueForKey: to every element of the array and returns an array of the results. If the elements in the receiving array are NSDictionaries, -valueForKey: is nearly the same as -objectForKey:. It will work as long as the key doesn't start with an #
To summarize all other answers:
Ruby (as in the question):
array.map{|o| o.name}
Obj-C (with valueForKey):
[array valueForKey:#"name"];
Obj-C (with valueForKeyPath, see KVC Collection Operators):
[array valueForKeyPath:#"[collect].name"];
Obj-C (with enumerateObjectsUsingBlock):
NSMutableArray *newArray = [NSMutableArray array];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[newArray addObject:[obj name]];
}];
Swift (with map, see closures)
array.map { $0.name }
And, there are a couple of libraries that allow you to handle arrays in a more functional way. CocoaPods is recommended to install other libraries.
Update: If you're using Swift, see map.
BlocksKit is an option:
NSArray *new = [stringArray bk_map:^id(NSString *obj) {
return [obj stringByAppendingString:#".png"];
}];
Underscore is another option. There is a map function, here is an example from the website:
NSArray *tweets = Underscore.array(results)
// Let's make sure that we only operate on NSDictionaries, you never
// know with these APIs ;-)
.filter(Underscore.isDictionary)
// Remove all tweets that are in English
.reject(^BOOL (NSDictionary *tweet) {
return [tweet[#"iso_language_code"] isEqualToString:#"en"];
})
// Create a simple string representation for every tweet
.map(^NSString *(NSDictionary *tweet) {
NSString *name = tweet[#"from_user_name"];
NSString *text = tweet[#"text"];
return [NSString stringWithFormat:#"%#: %#", name, text];
})
.unwrap;
I think valueForKeyPath is a good choice.
Sit below has very cool examples. Hopes it is helpful.
http://kickingbear.com/blog/archives/9
Some example:
NSArray *names = [allEmployees valueForKeyPath: #"[collect].{daysOff<10}.name"];
NSArray *albumCovers = [records valueForKeyPath:#"[collect].{artist like 'Bon Iver'}.<NSUnarchiveFromDataTransformerName>.albumCoverImageData"];
I'm no Ruby expert so I'm not 100% confident I'm answering correctly, but based on the interpretation that 'map' does something to everything in the array and produces a new array with the results, I think what you probably want is something like:
NSMutableArray *replacementArray = [NSMutableArray array];
[existingArray enumerateObjectsUsingBlock:
^(NSDictionary *dictionary, NSUInteger idx, BOOL *stop)
{
NewObjectType *newObject = [something created from 'dictionary' somehow];
[replacementArray addObject:newObject];
}
];
So you're using the new support for 'blocks' (which are closures in more general parlance) in OS X 10.6/iOS 4.0 to perform the stuff in the block on everything in the array. You're choosing to do some operation and then add the result to a separate array.
If you're looking to support 10.5 or iOS 3.x, you probably want to look into putting the relevant code into the object and using makeObjectsPerformSelector: or, at worst, doing a manual iteration of the array using for(NSDictionary *dictionary in existingArray).
#implementation NSArray (BlockRockinBeats)
- (NSArray*)mappedWithBlock:(id (^)(id obj, NSUInteger idx))block {
NSMutableArray* result = [NSMutableArray arrayWithCapacity:self.count];
[self enumerateObjectsUsingBlock:^(id currentObject, NSUInteger index, BOOL *stop) {
id mappedCurrentObject = block(currentObject, index);
if (mappedCurrentObject)
{
[result addObject:mappedCurrentObject];
}
}];
return result;
}
#end
A slight improvement upon a couple of the answers posted.
Checks for nil—you can use nil to remove objects as you're mapping
Method name better reflects that the method doesn't modify the array it's called on
This is more a style thing but I've IMO improved the argument names of the block
Dot syntax for count
For Objective-C, I would add the ObjectiveSugar library to this list of answers: https://github.com/supermarin/ObjectiveSugar
Plus, its tagline is "ObjectiveC additions for humans. Ruby style." which should suit OP well ;-)
My most common use-case is mapping an dictionary returned by a server call to an array of simpler objects e.g. getting an NSArray of NSString IDs from your NSDictionary posts:
NSArray *postIds = [results map:^NSString*(NSDictionary* post) {
return [post objectForKey:#"post_id"];
}];
For Objective-C, I would add the Higher-Order-Functions to this list of answers: https://github.com/fanpyi/Higher-Order-Functions;
There is a JSON array studentJSONList like this:
[
{"number":"100366","name":"Alice","age":14,"score":80,"gender":"female"},
{"number":"100368","name":"Scarlett","age":15,"score":90,"gender":"female"},
{"number":"100370","name":"Morgan","age":16,"score":69.5,"gender":"male"},
{"number":"100359","name":"Taylor","age":14,"score":86,"gender":"female"},
{"number":"100381","name":"John","age":17,"score":72,"gender":"male"}
]
//studentJSONList map to NSArray<Student *>
NSArray *students = [studentJSONList map:^id(id obj) {
return [[Student alloc]initWithDictionary:obj];
}];
// use reduce to get average score
NSNumber *sum = [students reduce:#0 combine:^id(id accumulator, id item) {
Student *std = (Student *)item;
return #([accumulator floatValue] + std.score);
}];
float averageScore = sum.floatValue/students.count;
// use filter to find all student of score greater than 70
NSArray *greaterthan = [students filter:^BOOL(id obj) {
Student *std = (Student *)obj;
return std.score > 70;
}];
//use contains check students whether contain the student named 'Alice'
BOOL contains = [students contains:^BOOL(id obj) {
Student *std = (Student *)obj;
return [std.name isEqual:#"Alice"];
}];
There is a special key-path operator for this: #unionOfObjects. Probably it replaced [collect] from previous versions.
Imagine a Transaction class with payee property:
NSArray *payees = [self.transactions valueForKeyPath:#"#unionOfObjects.payee"];
Apple docs on Array Operators in Key-Value coding.
Swift introduces a new map function.
Here is an example from the documentation:
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
(var number) -> String in
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
// strings is inferred to be of type String[]
// its value is ["OneSix", "FiveEight", "FiveOneZero"]
The map function takes a closure which returns a value of any type and maps the existing values in the array to instances of this new type.
I have an object called Station in my system with these attributes:
#interface Station : NSObject {
NSString *stationID;
NSString *callsign;
NSString *stationState;
}
I also have an NSMutableArray containing 20 'Station' objects as defined above.
I need to define a method which can can sort this array in 2 ways:
1) By stationID
2) By callsign
Can someone please explain how I can do this?
I'd use
NSInteger stationsSort( Station *station1, Station *station2, void *context) {
if ( station1_greater_than_station2 ) {
return NSOrderedDescending;
}
if ( station1_less_than_station2 ) {
return NSOrderedAscending;
}
return NSOrderedSame;
}
[myArray sortedArrayUsingFunction:stationsSort context:nil];
Have a look at NSPredicates. This can be used for query and sorting objects in Arrays.
Examples are here as well.
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Predicates/Articles/pUsing.html
And NSSortDescriptor - With examples.
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdFetching.html