Loop Through NSArray And Check Objects in Objective-C - objective-c

I'm trying to loop inside the objects of my array and would like to know how can I check the contents of the objects inside it and then do something when my search doesn't apply.
For example:
myArray = #[#"A1", #"A2", #"A3", #"B1", #"B2", #"B3", #"C1", #"C2", #"C3"];
I'd like to check the contents of myArray and if the object contains the letter A, I'll actually create a button until I create a row of buttons with objects of the letter A. If it contains a different letter, say B, I'll create a different row of buttons below the letter A row of buttons.
It will look like this:
[A1] [A2] [A3]
[B1] [B2] [B3]
[C1] [C2] [C3]
I'm thinking of doing a fast enumeration like this:
for (NSString *string in myArray)
{
if (// string has letter A)
{
Add string to array of A
}
else if (// string has letter B)
{
Add string to array of B
}
else if (// string has letter C)
{
Add string to array of C
}
}
But I'm not sure if I'm doing it right and fast.

This kind of approach might help indirectly. I'm not entirely sure what is being asked, so make of this what you will.
If you want to gather up by prefix, build an NSMutableDictionary whose keys will be #"A", #"B", ... and values are instances of NSMutableArray. For each string in your myArray, take it's prefix as the key to look up the array value in the dictionary, and add.
Something along the following lines:
NSArray *myArray = #[#"A1", #"A2", #"A3", #"B1", #"B2", #"B3", #"C1", #"C2", #"C3"];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (NSString *s in myArray) {
if ([s length] < 1) {
continue;
}
NSString *key = [s substringToIndex:1];
if (![dict objectForKey:key]) {
[dict setObject:[NSMutableArray array] forKey:key];
}
NSMutableArray *bucket = [dict objectForKey:key];
[bucket addObject:s];
}
This kind of approach, which again may not directly answer your question, might prove instructive. It also has the advantage of being extensible - no need for yet another if clause.
Edit: The output of 'po dict' above in the console reads
(lldb) po dict
$2 = 0x0a33e660 {
A = (
A1,
A2,
A3
);
B = (
B1,
B2,
B3
);
C = (
C1,
C2,
C3
);
}

Find the character in string by using NSRange and do ur stuff. Like this
Try :
for (NSString *string in myArray)
{
if ([string rangeOfString:#"A"].location != NSNotFound)//Contains "A"
{
Add string to array of A
}
else if ([string rangeOfString:#"B"].location != NSNotFound)//Contains "B"
{
Add string to array of B
}
else if ([string rangeOfString:#"C"].location != NSNotFound)//Contains "C"
{
Add string to array of C
}
}
ope this helps u.

Related

Scanning for doublets in an array after equating upper and lower case letters

I'm reading in a file, containing words and names, as a string. Then I'm breaking it into an array of strings. What I want to do is to print out the names that are also words. The words are spelled with only lower case letters and the names has a capital first letter. Thus, I want to order upper and lower cases the same so that Ii then can scan the array and receive the duplicates.
So what I have in my main.m file looks like this now:
int main(int argc, const char * argv[])
{
#autoreleasepool {
// insert code here...
NSString *wordString = [NSString stringWithContentsOfFile:#"/usr/share/dict/words"
encoding:NSUTF8StringEncoding
error:NULL];
NSArray *words = [wordString componentsSeparatedByString:#"\n"];
Everywhere it says I should use a caseIntensiveCompare method, but I don't understand how it works, or how to use it in this particularly case.. When I search for it on google all I get is this:
NSString *aString = #"ABC";
NSString *bString = #"abc";
if ([aString caseInsesitiveCompare: bString]) == NSOrderedSame)
{
//The strings are ordered equal
}
It seems wrong, firstly because I only have the one string, and secondly I want it to actually order them the letters the same, not to check if they are ordered the same..
If someone could give me a hint of how to do this I would be VERY thankful!
Thanks in advance // Bjoern
Not sure whether i have understand your question properly. But how much i understood is you need to first store array string in mutable set then on the basis of that you can compare the existing one to the new one as represent below code. So that like that you can filter your array as well as identify duplicate both words and names. Below assuming words is you array which contains string values. So on the basis of that processing the further code.
NSMutableSet* existing = [NSMutableSet set];
NSMutableArray* newArray = [NSMutableArray
array];
for (id object in words) {
if (![existing containsObject:[[object
name]lowercaseString]) {
[existing addObject:[[object
name]lowercaseString];
[newArray addObject:object];
}
else
{
NSLog(#"duplicate name=%#", [object name]);
}
}
You could try something like this (explanation in the comments):
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
NSString *wordString = [NSString stringWithContentsOfFile:#"/usr/share/dict/words"
encoding:NSUTF8StringEncoding
error:NULL];
// Get all the words by separating on newlines & convert to lowercase
// Note: Assuming that the list doesn't contain duplicate strings
// (i.e. the same word or name twice)
// If it does, you should separate/add_to_set/get_all_objects/lowercase instead
NSArray *words = [[wordString componentsSeparatedByString:#"\n"]
valueForKey:#"lowercaseString"];
// Create a counted set to keep track of duplicate strings
NSCountedSet *bag = [[NSCountedSet alloc] initWithArray:words];
// Create a mutable set to add only duplicates
NSMutableSet *duplicates = [NSMutableSet setWithCapacity:0];
// Iterate and add words that appear more than once in the counted set
for (NSString *word in bag) {
if ([bag countForObject:word] > 1) {
[duplicates addObject:word];
}
}
NSLog(#"Words: %lu | Unique words: %lu | Duplicates: %lu", words.count, bag.count, duplicates.count);
// Output => Words: 235887 | Unique words: 234372 | Duplicates: 1515
}
}
Now duplicates is a Set of the strings that are both words & names (as per your requirement i.e. they only differ in the capitalization). You can get an array of the words by sending [duplicates allObjects].

How to remove elements of NSDictionary

I have NSArray of NSDictionaries I need to extract 2 values or remove the values I don't need from the dictionary in the example below I need to remove id and NumberValue. any of you knows how can I do that?
Array: (
{
customerUS= {
DisplayName = "level";
InternalName = "Number 2";
NumberValue = 1;
id = xwrf
},
customerCAN= {
DisplayName = "PurchaseAmount";
InternalName = "Number 1";
NumberValue = 3500;
id = adf;
};
}
)
I'll really appreciate your help.
First thing, You can not remove/insert/update value in (immutable) NSDictionary/NSArray you need to convert NSDictionary/NSArray to (mutable) NSMutableDictionary/NSMutableArray.
such like
NSArray *myArr = ....;
NSMutableArray *newMutableArr = [myArr mutableCopy];
Then you can change in newMutableArr.
Such like
for(int i = 0 ; i < newMutableArr.count ; i ++)
{
[[newMutableArr objectAtIndex:i] removeObjectForKey:#"id"];
[[newMutableArr objectAtIndex:i] removeObjectForKey:#"NumberValue"];
}
EDITED:
Without Use of for loop and removeObjectForKey, if you have array of dictionary and both are mutable then you can also delete a key and its object from all elements of the array like this:
[newMutableArr makeObjectsPerformSelector:#selector(removeObjectForKey:) withObject:#"id"];
[newMutableArr makeObjectsPerformSelector:#selector(removeObjectForKey:) withObject:#"NumberValue"];
I would advice you to read Apple documents.
For modifying any Collection object after it is created, you need the mutable version.
For NSDictionary we have NSMutableDictionary. Read here.
We have a method for removing objects:
- (void)removeObjectForKey:(id)aKey
There are other methods as well. You can easily refer them in the above mentioned documentation.
Find out removeObjectForKey for deleting record from NSMutabledictionary.
removeObjectForKey pass the key value whatever you have like
all this are your key
DisplayName,
InternalName,
NumberValue,
id
do like this
removeObjectForKey:#"id";
First of all you have to convert the array to mutable array and then you can remove the key-value pairs from dictionary.
NSMutableArray *mutableArray = [yourArray mutableCopy];for(int i=0;i<mutableArray.count;i++){ NSMutableDictionary *outerDictionary = [mutableArray objectAtIndex:i]; for(NSString *key in outerDictionary.allKeys){ NSMutableDictionary *innerDictionary = [outerDictionary objectForKey:key]; [innerDictionary removeObjectForKey:#"id"]; [innerDictionary removeObjectForKey:#"NumberValue"]; }
}

Array Issue in Objective C Xcode

I have a problem with my algorithm for calculating a sore. The user enters a word into the UITextField, and if the word matches a string in the array (#"The Word") the int 'score' will be added by 1.
Then the int score is set as a label as the user gets a word right. (DISPLAYING THE SCORE)
THE PROBLEM, a user can just keep on entering the same word over and over again and the score will keep going up by one. IS there a command for knowing if a word has already been entered, so you can only use the word once.
The Code
NSArray *scoreArray1 = [NSArray arrayWithObjects:
#"Word 1", #"Word 2", #"Word 3", nil];
NSString *inputtwo =_EnterNameText.text;
BOOL isItright = NO;
for(NSString *possible in scoreArray1) {
if([inputtwo isEqual:possible] ) {
isItright = YES;
break;
}
}
if(isItright) {
static int myInt = 0;
myInt++;
NSString *score = [NSString stringWithFormat:#"%d", myInt];
[_scorelabel setText:score];
}
UPDATE!!!!!!
NSArray *scoreArray1 = [NSArray arrayWithObjects:
#"Alan Shearer", #"Shearer", #"Andrew Cole", #"Andy Cole", #"Cole", #"Thierry Henry", #"Henry", #"Robbie Fowler", #"Fowler", #"Frank Lampard", #"Lampard", #"Michael Owen", #"Owen", nil];
NSSet *set2 = [NSSet setWithArray:scoreArray1];
NSString *inputtwo =_EnterNameText.text;
BOOL isItright = NO;
for(NSString *possible in set2) {
if([inputtwo isEqual:possible] ) {
isItright = YES;
break;
}
}
if(isItright) {
static int myInt = 0;
myInt++;
NSString *score = [NSString stringWithFormat:#"%d", myInt];
[_scorelabel setText:score];
}
HOWEVER NOW THE APP DOES NOT WORK, IT CRASHES, any suggestions?
Why don't you keep a second Array where you store the given (correct) answers.
Whit this you can just do a contains inside your if....problem solved.
a second option is not to put string in your array but "Answer" Objects, that have a field that you can flag as already used.
You could just create an NSMutableSet and put a copy of the word into there whenever one is entered. Then you just need to check if the word exists in the set before incrementing the score.
I'm suggesting a set because it uses hashed access, so lookups are fast. Also, if you add the same string more than once, the set will still only have one reference to the string.
Actually, if you have an array of "legal" words, the way to go is to simply remove each word as it's called out, until the array gets to be zero entries long.
NSMutableArray* scoreArrayCopy = [NSMutableArray arrayWithArray:scoreArray];
int originalCount = scoreArrayCopy.count;
...
while (scoreArrayCopy.count > 0) {
NSString* guess = <get next guess>;
[scoreArrayCopy removeObject:guess];
score = originalCount - scoreArrayCopy.count;
}
(If you have a lot of words things would be more efficient if you used an NSMutableSet instead of an NSMutableArray, but the logic would be the same.)

Objective C : Writing into a Plist

Even though i know there are at least 2 or 3 topics with this name, i didnt find a proper answer so far to my problem :
I want to edit a Plist (which has been created by zwoptex (image/animations program)) in order to divide every number in it by 2.
So in my plist i do have some keys like "spriteOffset" with {{182, 160}, {58,75}} or {192, 165} as value. Those are NSStrings, and i just want to modify the numbers so i need to check if there's a "{" or a space or such, then casting the number.
The thing is i don't really know how to do it.....
Also, it seems that i'm missing something with my plist management. I've put some NSLogs for displaying every of those strings in my plist, but.... nothing gets displayed...
So here is my code :
-(void)DivideValues
{
for(NSString * plistName in plistSubpathsByName)
{
NSMutableDictionary* infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:#"%#.plist",plistName]];
for(NSDictionary * sprite in [infoDict objectForKey:#"frames"])
{
for(NSString * string in [infoDict objectForKey:#"spriteColorRect"])
{
NSLog(#"%#",string);
}
for(NSString * string in [infoDict objectForKey:#"spriteOffset"])
{
NSLog(#"%#",string);
}
for(NSString * string in [infoDict objectForKey:#"spriteSize"])
{
NSLog(#"%#",string);
}
for(NSString * string in [infoDict objectForKey:#"spriteSourceSize"])
{
NSLog(#"%#",string);
}
for(NSString * string in [infoDict objectForKey:#"textureRect"])
{
NSLog(#"%#",string);
}
}
}
}
Thanks for any response, and i wish you all good luck for your career/passion
First of all, you should replace [infoDict objectForKey:#"spriteColorRect"] with [sprite objectForKey:#"spriteColorRect"], since the sprite is probably the dict containing further information.
You don't see any logs because -objectForKey: returns nil for a key that does not exist.
For changing the values, you might try to create a CGPoint or CGRect from the string, then changing it and finally converting it back to a string. (CGPointFromNSString() and NSStringFromCGPoint)
To save the modified version of your dictionary use NSDictionary's -writeToFile:atomically:.
The reason you example logs nothing is most likely because your inner for..in loops are probably looking in the wrong dictionary: the outer loop gets a dictionary sprite, so shouldn't the inner loops be looking at keys in that dictionary?
If you want to read a property list in, change some values in it, and write the same property list back out, you might find it useful to look at the NSPropertyListSerialization class -- it lets you quickly get a structure of mutable arrays/dictionaries from plist data, so you can iterate into them however you'd like to change values within, then serialize the whole thing back to data again. (If you use dictionaryWithContentsOfFile: you'll get a mutable dictionary, but all the containers within it will be immutable, so you'd have to do mutableCopy and swizzle contents all over the place during your iteration.)
No time to write up more detail at the moment, but I might edit the answer later if looking up the docs for NSPropertyListSerialization doesn't help you.
Ok I did succeed so if anyone is interested here is the code :
-(void)DivideValues
{
for(NSString * xflName in [xflSubpathsByName objectEnumerator]){
NSMutableDictionary* infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:[sourceFolder stringByAppendingPathComponent:xflName]];
NSDictionary * dictionary = [infoDict objectForKey:#"frames"];
NSMutableDictionary * mutabledictionary = [[dictionary mutableCopy] autorelease];
for(NSString * pngFileName in dictionary) {
NSDictionary * sprite = [dictionary objectForKey:pngFileName];
NSLog(pngFileName);
NSMutableDictionary * mutablesprite = [[sprite mutableCopy] autorelease];
NSString * newstring = [self castSpriteRect:[sprite objectForKey:#"spriteColorRect"]];
[mutablesprite setObject:newstring forKey:#"spriteColorRect"];
newstring = [self castSprite:[sprite objectForKey:#"spriteOffset"]];
[mutablesprite setObject:newstring forKey:#"spriteOffset"];
newstring = [self castSprite:[sprite objectForKey:#"spriteSize"]];
[mutablesprite setObject:newstring forKey:#"spriteSize"];
newstring = [self castSprite:[sprite objectForKey:#"spriteSourceSize"]];
[mutablesprite setObject:newstring forKey:#"spriteSourceSize"];
newstring = [self castSpriteRect:[sprite objectForKey:#"textureRect"]];
[mutablesprite setObject:newstring forKey:#"textureRect"];
[mutabledictionary setObject:mutablesprite forKey:pngFileName];
}
[infoDict setObject:mutabledictionary forKey:#"frames"];
[infoDict writeToFile:[sourceFolder stringByAppendingPathComponent:xflName] atomically:NO];
}
if(!cancelling)
++digestStage;
else
digestStage = End;
}
-(NSString *)castSprite:(id)obj{
CGPoint point = NSPointFromString((NSString *)obj);
int i = (int)point.x%2 == 0 ?(int)point.x/2:1+(int)point.x/2;
int j = (int)point.y%2 == 0 ?(int)point.y/2:1+(int)point.y/2;
NSString * res = [NSString stringWithFormat:#"{%d, %d}",i,j];
return res;
}
-(NSString *)castSpriteRect:(id)obj{
CGRect point = NSRectFromString((NSString *)obj);
int i = (int)point.origin.x%2 == 0 ?(int)point.origin.x/2:1+(int)point.origin.x/2;
int j = (int)point.origin.y%2 == 0 ?(int)point.origin.y/2:1+(int)point.origin.y/2;
int y = (int)point.size.width%2 == 0 ?(int)point.size.width/2:1+(int)point.size.width/2;
int x = (int)point.size.height%2 == 0 ?(int)point.size.height/2:1+(int)point.size.height/2;
NSString * res = [NSString stringWithFormat:#"{{%d, %d}, {%d, %d}}",i,j,y,x];
return res;
}

how to sort an NSArray with a nested NSArray

Hi I'm new with the Objective-C and i try to do some try.
I have an NSArray called "values". It is an array of array. It seems like :
["0" = > "aString",6872,5523,0091]
["1" = > "anotherString",4422,1234,0091]
["2" = > "aString",6812,2143,0314] ...
How do I sort the "values" array than the first integer value?
I should use the NSPredicate ?
please help me with some example.
thanks
Something like that with block (assuming that your integer value are NSNumber or some class that can be compared):
NSArray *sortArray = [yourArray sortedArrayUsingComparator: ^(id elt1, id elt2) {
return [[elt1 objectAtIndex:1] compare:[elt2 objectAtIndex:1]];
} ];