Merging values of an Array - objective-c

I have an array that contains all the names that I get from JSON
NSArray *name = [newResponseObject valueForKey:#"name"];
I also have another array that contains all the last names that I get from JSON.
NSArray *lastname = [newResponseObject valueForKey:#"lastname"];
What I want to do achieve is creating another array that contains [name, lastname] and I want to display the values for my picker view. for example "John Smith".
I have tried using arrayWithArray but that just added all the values into one array.
What is the correct method to achieve this ?

Depending on what you're planning on doing with them afterwards should dictate how you decide to store them. As #Woodstock mentioned you can store them in an array of concatenated strings "name lastname" similar to option 1 from below.
But from your description it sounds like you may want to store them as an array of arrays similar to option 2 from below.
// option 1 storing them in concatonated strings
NSArray *firstNames = #[#"John", #"Ralph", #"Bob"];
NSArray *lastNames = #[#"Smith", #"Jones", #"Miller"];
NSMutableArray <NSString *> *firstAndLastNames = [NSMutableArray array];
for (NSInteger index = 0; index < firstNames.count; index++) {
[firstAndLastNames addObject:[NSString stringWithFormat:#"%# %#", [firstNames objectAtIndex:index], [lastNames objectAtIndex:index]]];
}
NSLog(#"First and last names = %#", firstAndLastNames);
// option 2 storing them in arrays
NSMutableArray <NSArray *> *firstAndLastNamesInArray = [NSMutableArray array];
for (NSInteger index2 = 0; index2 < firstNames.count; index2++) {
[firstAndLastNamesInArray addObject:#[[firstNames objectAtIndex:index2], [lastNames objectAtIndex:index2]]];
}
NSLog(#"First and last names in array = %#", firstAndLastNamesInArray);
Which would result in outputs of:
Option 1:
First and last names = (
"John Smith",
"Ralph Jones",
"Bob Miller"
)
Option 2:
First and last names in array = (
(
John,
Smith
),
(
Ralph,
Jones
),
(
Bob,
Miller
)
)
The benefit of using the second option is if you want to just get the first name or last name you can just find it by index (rather than having to attempt to separate the first and last names by space -- some first or last names also have spaces in them so this could mess up your logic of trying to fetch just one of the names if you use option 1).
i.e. using option 2 you can find the last name of the 3rd person by doing this:
[[firstAndLastNamesInArray objectAtIndex:2] objectAtIndex:1]
Another option would be to create a Person object and have it have properties firstName and lastName and then store an array of Person objects instead.
One other thing you didn't mention as well (but I'm assuming is true), is are these arrays you're fetching from the server in the correct order -- i.e. does firstName[3] correlate with lastName[3]? Also are you always guaranteed to have a firstName and lastName for each person?

There are lots of ways to achieve this.
Probably the easiest is to concatenate at source.
NSArray *fullName = [NSString stringWithFormat:#"%# %#", [newResponseObject valueForKey:#"name"], [newResponseObject valueForKey:#"lastname"]];

Related

Sort an NSDictionary into an NSMutableArray but keep value and key?

I'm a little confused: trying to take a list of player names and scores that I have in an NSDictionary, and sort them into score order (highest score first). I know I can't sort a Dictionary so I need to move the data into an array first, but in doing so, won't I have to lose one half of each dictionary key/value pair?
For example, let's say I have the following pairs:
Bill / 10000
John / 7500
Stan / 7500
Mark / 5000
If I go and take the scores out and sort them, then retrieve the keys later, won't John and Stan get mixed up since they had identical scores? Might it call one of them twice, etc?
I realise I can't sort the dictionary, but is there a smarter way to do this?
What you could do is to get a sorted array of your players based on their score, and then create a dictionary for each player and append them in another array. Something like this perhaps (I'm using the new literals syntax, use the old one if appropriate):
NSDictionary *scores = #{
#"Stan" : #7500,
#"Mark" : #5000,
#"John" : #7500,
#"Bill" : #10000
};
NSArray *sp = [scores keysSortedByValueUsingComparator:^(id obj1, id obj2){
return [obj2 compare:obj1];
}];
NSMutableArray *players = [NSMutableArray arrayWithCapacity:0];
for (NSString *p in sp) [players addObject:#{ #"name":p, #"score":scores[p] }];
Now your players array is:
(
{
name = Bill;
score = 10000;
},
{
name = John;
score = 7500;
},
{
name = Stan;
score = 7500;
},
{
name = Mark;
score = 5000;
}
)
PS. Is not a good idea to keep a dictionary where the keys are player names, consider that you got 2 different John players... what would happen then? Also a better solution imo would be to create a Player class and keep their data (score, name etc) as properties.
You'll have to create two arrays, one for the score and another for the player. The key point being that the player array is in the same order as the (sorted) score array. The implementation below assumes you keep the score using an NSNumber object, and is not particularly efficient as it sorts the values twice:
(untested)
NSDictionary *dict = ...; // key=player (NSString), value=score (NSNumber).
NSArray *scores = [[dict allValues] sortedArrayUsingComparator:^(id obj1, id obj2) {
return [(NSNumber *)obj2 compare:(NSNumber *)obj1];
}];
NSArray *players = [dict keysSortedByValueUsingComparator:^(id obj1, id obj2) {
return [(NSNumber *)obj2 compare:(NSNumber *)obj1];
}];

Getting Top 10 Highest Numbers From Array?

I am having a bit of a issue. I have an NSMutableDictionary with 10 NSMutableArrays in it. Each array has somewhere between 0-10 numbers which could each be any integer, e.g. 12 or 103.
What I need to do is get the top 10 highest numbers from across each of the arrays. The trouble is, I need to keep a reference of the array it came from in the dictionary (the key) and the index position of the number from the array it came form.
Easiest way, is to sort the array in Descending order, and then grab the first 10 indexes
Or if they are inside dictionaries, iterate the dictionary allValues, grab all the arrays, add all the elements inside a common array, and sort that
It seems as if the data structure you want to end up with is an array of objects, where each object is functionally similar to an "index path" except that it's composed of a string (key) and a value (offset).
Assuming that the actual search for highest numbers isn't in question, then I'd suggest creating one of these objects whenever you find a candidate number so that, once the top ten are found, the objects can be used as back-pointers to the numbers' source locations.
Sounds like some sort of homework :)
So you have this:
NSMutableDictionary* source = [#{
#"1" : #[ #10, #20, #100 … ],
#"2" : #[ #8, #42, #17 … ]
} mutableCopy];
So lets start by creating another arrangement:
NSMutableArray* numbers = [NSMutableArray new];
for (NSArray* array in source.allValues)
{
for (NSNumber* number in array)
{
[numbers addObject: #{ #"number" : number, #"parent" : array }];
}
}
This is what we get:
#[
#{ #"number" : #10, #"parent" : <array> },
#{ #"number" : #20, #"parent" : <array> },
…
]
Now we can sort and find the numbers you wanted.
[numbers sortUsingComparator: ^( id lhs, id rhs ){
return [((NSDictionary*) rhs)[#"number"] compare: ((NSDictionary*) lhs)[#"number"]];
}];
NSArray* topNumbers = [numbers subarrayWithRange: NSMakeRange( 0, 10 )];
Here we are. topNumbers contains the numbers you needed along the source array.
This is quite a naive way to do it. It can be optimized both in CPU time and memory usage by a fair amount. But hey, keep it simple is not a bad thing.
Not addressed: what if the tenth and eleventh numbers are equal? (adressed here: Pick Out Specific Number from Array?) range checks. not tested, not even compiled. ;)
Walk through the arrays creating an object/structure for each element, consisting of the numeric "key" value and the "path" (array indices) to the element. Sort the objects/structures so created. (This is referred to as a "tag sort".)
The other approach, if you only need the top N values (where N << total number of entries) is to create an array of N elements, consisting of the above key and path info. Scan through all the arrays and compare each array element to the smallest key of the N currently stored. If you find an element larger than the smallest stored, replace the smallest stored and sort the N elements to select a new smallest stored.
You have to short your array in descending order using 'C' logic. Here i'm going to give an example according to your condition....
// adding 20 elements in an array, suppose this is your original array (array1).
NSMutableArray *array1 = [[NSMutableArray alloc]init];
for(int i=0;i<20;i++)
{
NSString *str = [NSString stringWithFormat:#"%d",(i*4)];
[array1 addObject:str];
}
//make a copy of your original array
NSMutableArray *array2 = [[NSMutableArray alloc]initWithArray:array1];
// this is the array which will get your sorting list
NSMutableArray *array3 = [[NSMutableArray alloc]init];
//declare an integer for compare as a maximum number and it to 0 initially
int max = 0;
// this is the logic to sort an array
for(int i=0;i<20;i++)
{
for(int j=0;j<[array2 count];j++)
{
int f = [[array2 objectAtIndex:j] intValue];
if(max<f)
{
max = f;
}
}
NSString *str = [[NSNumber numberWithInt:max]stringValue];
//max has a maximum value then add it to array3 and remove from array2
//for a new shorting
[array3 addObject:str];
[array2 removeObject:str];
// set 0 to max again
max = 0;
}
//now after all procedure print the **array3**
// and you will get all the objects in descending order,
//you can take top **10** variables from **array3**
NSLog(#"your sorting array %#", **array3**);
}

Reverse UILabel.text value

I've got a program that I'm finishing up that is a name generator. Right now it takes a random value from 2 separate arrays, concatenates them and displays the result as the label. text -- I want to have a button that reverses the label text (instead of John Doe, it would say Doe John). This is the code I'm using to do this. My thinking is that I use the same values from the arrays and then assign the string to a variable for use later in another method called "reverseNameValue" or something. It's not working :) When I click the "reverse" button, it shows me a different name altogether. Any advice?
- (IBAction)generateBName:(id)sender {
int a = arc4random() % 3;
int b = arc4random() % 3;
// populate the array for the names
NSArray *firstNameArray = [NSArray arrayWithObjects: #"Jacob",
#"Ethan",
#"Justin", nil];
NSArray *middleNameArray = [NSArray arrayWithObjects: #"Jose",
#"Jeremiah",
#"Julian", nil];
// concatenate strings at index of array
NSString *fullName = [NSString stringWithFormat:#"%# %#", [firstNameArray objectAtIndex:a], [middleNameArray objectAtIndex:b]];
NSString *reverseName = [NSString stringWithFormat:#"%# %#", [firstNameArray objectAtIndex:b], [middleNameArray objectAtIndex:a]];
// display the newly created first & middle names
reverseNameString = reverseName;
babyname.text = fullName;
And the reverse method:
- (IBAction)reverseLabel:(id)sender {
babyname.text = reverseNameString;
}
the line where you set the reverseName string has the names backwards, so it is grabbing a firstname and then a middlename but with reversed indexes. It should be:
NSString *reverseName = [NSString stringWithFormat:#"%# %#", [middleNameArray objectAtIndex:b],[firstNameArray objectAtIndex:a]];

Faster NSArray lookup using NSDictionary storing indices as values

Lets say I have a Student class as below:
class Student {
NSNumber *id;
NSString *lastName;
NSString *firstName;
}
Now when I get the records of all the students from a web service, I have an NSArray that stores records for all the students. At some point of time I need to look up the array to find a particular student's record based upon first name.
Assume I create a dictionary called studentsFirstNameDictionary.
So while adding objects to students array, I can do
Student objStudent = [[Student alloc] init];
objStudent.Id = someId;
objStudent.firstName = someName;
objStudent.lastName = someLastName;
[studentsDictionary setValue:iterationCounter forKey:objStudent.firstName];
[students addObject:objStudent];
I want to know if it is a good idea to create this dictionary to speed up the look up as below. Also please assume that in any case the array is required and for fast lookup I am creating other dictionaries too storing the last name and id as keys and indices as values like above:
-(Student*)getStudentByFirstName:(NSString *)firstName {
int idxOfStudent = [ studentsDictionary valueForKey:firstName];
return [students idxOfStudent];
}
Do you think this approach is performance wise better than having to iterate through the students array and compare the first name and return the matching student record?
I always need the students array because I need to populate a table view with that array. I am wondering if it is wise to create multiple dictionaries while populating the array so that I can look up a student record faster by fist name, last name or Id?
P.S.: For sake of simplicity, consider that all students have unique first name, last name and id so there will not be any issue while creating dictionaries storing first name, last name or ID as a value.
This sounds more complicated than it needs to be. Generally in Cocoa, if you find yourself consulting a data structures textbook for this common a task, either you've missed something in the Foundation docs or you're optimizing prematurely.
Given an array of Student objects, there are at least a couple of quick and easy ways to get the one with a unique attribute:
use a block test:
NSUInteger index = [studentArray indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj.firstName isEqualToString:desiredFirstName]) {
*stop = YES; // keeps us from returning multiple students with same name
return YES;
} else
return NO;
}];
if (index != NSNotFound)
Student *desiredStudent = [studentArray objectAtIndex:index];
use a predicate:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"firstName LIKE %#", desiredFirstName];
NSArray *filteredArray = [studentArray filteredArrayUsingPredicate:predicate];
Student *desiredStudent = [lastObject]; // only object if we assume firstNames are unique
Both of these assume your Student class has declared properties (or KVC-complient accessors) for those fields (that is, not just instance variables).
If you find yourself frequently accessing students by name, you might want to consider a dictionary mapping names to Student objects:
NSMutableDictionary *studentsByName = [NSMutableDictionary dictionaryWithCapacity:[students count]];
for (Student *student in students)
[studentsByName setObject:student forKey:[student firstName]];
If you have a very large number of students and want to search them by various attributes, you might consider learning about Core Data.
I don't think you need the array at all.
Create your Student objects:
Student objStudent = [[Student alloc] init];
objStudent.Id = someId;
objStudent.firstName = someName;
objStudent.lastName = someLastName;
[studentsDictionary setObject:student forKey:objStudent.firstName];
To look up a student by firstName:
Student * theStudent = [ studentsDictionary objectForKey:firstName ] ;
To get all Student objects from studentsDictionary, use
NSArray * allStudents = [ studentsDictionary allValues ] ;
This assumes you will only be finding students by their firstName attribute however.. #rickster's solution might be better in general

count NSMutableArray size till or from a specific word?

I have got an array, I know how to count its elements, but I need to count elements until a specific word:
NSMutableArray *whatBondInFrame;
whatBondInFrame=[NSMutableArray arrayWithObjects:#"red",#"red",#"red",#"gray",#"red",#"ran",#"gray",#"gray",nil];
I know [ whatBondInFrame count] but, let's say I want to know how many elements I have till the first gray or from the word "ran".
How would I get that?
This isn't tested but it should work:
int loc = 0;
for (loc; loc < [array count]; loc++) {
NSString *str = [array objectAtIndex:loc];
if ([str isEqualToString:#"ran"])
break;
}
int length = array.count-loc;
this gives you the count from the first element named ran.
If you want to know how many elements there are before (till) the word 'ran' then replace the last line with
int length = loc
The NSArray method:
- (NSUInteger)indexOfObject:(id)anObject
Will return the index of the first occurrence on an object, so you can do:
NSUInteger firstRanIndex = [whatBondInFrame indexOfObject:#"ran"];
There is a companion method:
- (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range
Which restricts the search to a given range of the array. There is no method to find the last occurrence, for that you must loop with the above methods.
In conjunction with the count method you can get the numbers you want.