I am trying to get the last NSString from a NSMutableArray, and delete it if it's empty.
Here is the code I am using:
- (void)viewWillAppear:(BOOL)animated {
if ([notes.data length]==0){
[storedText removeLastObject];
}
[self.tableView reloadData];
}
data is the NSString and storedText is the NSMutableArray. This code deletes the NSString even if it's not empty. I want it to keep the string if it contains text.
You should try something like this:
- (void)viewWillAppear:(BOOL)animated {
if ([[[storedText lastObject] data] length]==0){
[storedText removeLastObject];
}
[self.tableView reloadData];
}
BTW, it seems that your hypothesis that notes.data is the same string as the last object in storedText is not correct. This leads me to suspect that you have other kinds of errors in your code that you should also investigate. In other words, what you can expect is that your notes.data is not correct -- indeed, you should at least "update" it after you remove the last object from the array:
- (void)viewWillAppear:(BOOL)animated {
if ([[[storedText lastObject] data] length]==0){
[storedText removeLastObject];
notes = [storedText lastObject]; //-- this will be the *new* last object after removal
}
[self.tableView reloadData];
}
but I have no clue what you do with notes.data, so I do not know if this by itself is enough to bring it back to being consistent with your hypothesis.
Ideally before you add any item to storedText you would check that it wasn't nil or an empty string, then you wouldn't have the problem.
Otherwise, get the last item from storedText and check it (using isEqualToString: or a length check) and then remove it if it matches.
Follow what Wain said. Do this.
//total array size
int count = [storedText count];
int lastItemIndexInt = count - 1;
//get last object in array which is a string
NSString *str1 = [storedText objectAtIndex:lastItemIndexInt];
if ([str1 isEqualToString:#""] || [str1 length] < 1)
{
//string is null / blank, remove it
[storedText removeObjectAtIndex:lastItemIndexInt];
}
Related
I'm new to IOS and I'm not sure if I'm on the right track. What I need to know is if I'm on the right track and if I'm off it a hint on what to fix so I can get back on track. The mutable Array should read an array of speakers and say "Hello, my name is <speakerArray>" it should do that 8 times with a different name each time. This is what I Have:
- (NSArray*)badgesForSpeakers:(NSArray*)speakers {
for(speakers i = 0; i => 7; i++)
{
NSString *greetings =#"Hello, my name is .";
NSMutableArray *badges = [speakers arrayByAddingObjectsFromArray:greetings];
}
return badges;
}
Let's take this one step at a time. First of all, your operator in the loop is wrong; you mean to execute while i is less than or equal to 7. Thus, change => to <=. However, it's more stylish to say i < 8. And finally, it's most stylish of all to use what's called "Fast Enumeration", which allows you to loop without an index at all. In fact, it will work no matter how many items are in your speakers array! That takes us here:
- (NSArray*)badgesForSpeakers:(NSArray*)speakers {
for (NSString* speaker in speakers)
{
NSString *greetings =#"Hello, my name is .";
NSMutableArray *badges = [speakers arrayByAddingObjectsFromArray:greetings];
}
return badges;
}
Next, greetings isn't an array! It's a string. That's why calling -arrayByAddingObjectsFromArray: doesn't make any sense, and why the compiler isn't going to like it. Let's make its name singular, greeting, to reflect this fact. Strategy: Your goal here is to create an empty array, then construct items one by one and add them to that array. That takes us to:
- (NSArray*)badgesForSpeakers:(NSArray*)speakers {
NSMutableArray *badges = [NSMutableArray array]; //Here we make an empty array
for (NSString* speaker in speakers)
{
NSString *greeting =#"Hello, my name is .";
[badges addObject:greeting]; //Here we add one item to it each time 'round the loop
}
return badges;
}
Last, your string has no interpolation right now! It reads literally "Hello, my name is ." We do string interpolation using the -stringWithFormat: method.
Finished Product:
- (NSArray*)badgesForSpeakers:(NSArray*)speakers {
NSMutableArray *badges = [NSMutableArray array];
for (NSString* speaker in speakers)
{
NSString *greeting = [NSString stringWithFormat:#"Hello, my name is %#.",speaker];
[badges addObject:greeting];
}
return badges;
}
That should get you started with fast enumeration and string interpolation. Remember to compile your code often and try to understand the compiler errors--it would have helped you with some of these issues.
Maybe you mean this
- (NSMutableArray *)badgesForSpeakers:(NSArray *)speakers {
NSMutableArray *badges = [[NSMutableArray alloc] init];
for (NSString *speaker in speakers) {
[badges addObject:[NSString stringWithFormat:#"Hello, my name is %#", speaker]];
}
return badges;
}
plz use this code
- (NSArray*)badgesForSpeakers:(NSArray*)speakers {
NSMutableArray *badges = [NSMutableArray alloc];
for(int i = 0; i < speakers.count; i++)
{
NSString *greetings =[NSString stringWithFormat:#"Hello, my name is .%#",[speakers objectAtIndex:i]];
badges = [speakers addObject:greetings];
}
return [badges copy];
}
I'm checking is first letter of string is 0, if it is remove it and call again method to check is there is still 0. I've debugged this and it seems like when it accomplish number without 0, it goes backwards. Code:
-(NSString *)deleteZerosOnFirst:(NSString *)card
{
NSString *firstLetter = [card substringToIndex:1];
if ([firstLetter isEqualToString:#"0"]) {
card = [card substringFromIndex:1];
[self deleteZerosOnFirst:card];
NSLog(#"CARD: %#", card);
return card;
}
else {
NSLog(#"CARD: %#", card);
return card;
}
}
The main problem is that you're not using the result of the recursion. The line of code where you call yourself should say this:
card = [self deleteZerosOnFirst:card];
Also, you're calling deleteZerosOnFirst before you do the NSLog. Reverse the order of these two lines. That will at least give you your debug output in the right sequence.
Here's your recursive call:
[self deleteZerosOnFirst:card];
That doesn't modify the string that card references. It creates and returns a new string. You're ignoring the returned string. You want this:
card = [self deleteZerosOnFirst:card];
But this is really a lot simpler:
#implementation NSString (withoutLeadingZeroes)
- (NSString *)withoutLeadingZeroes {
NSString *s = self;
while ([s hasPrefix:#"0"]) {
s = [s substringFromIndex:1];
}
return s;
}
#end
how do i check if an item exists and if it does replace it in NSMutableArray i just cant figure it out all i have so far is:
int i = [arrayOne indexOfObject:#"object to replace"];
NSLog(#"%#", i);
[arrayOne replaceObjectAtIndex:i withObject:#"replace"];
but i keep getting errors :S can anyone help me ?
My array is:
#[ "13L6-A67-1", "13NAPUSD-A1", "13NASUWO-X1", "13NASUWO-X1", "13ASECON-D1", "13ASECON-D1", "13ASECON-D1", "13ASECON-D1", "13ASMATH-C1", "13ASMATH-C1", "13ASMATH-C1", "13ASMATH-C1", "13ASPHYS-B1", "13ASPHYS-B1", "13ASPHYS-B1", "13ASPHYS-B1", "13B3ITCE-F1", "13B3ITCE-F1", "13B3ITCE-F1", "13B3ITCE-F1" ]
if object is not present in array NSNotFound value is returned, so you need to check for it:
if (i != NSNotFound)
[arrayOne replaceObjectAtIndex:i withObject:#"replace"];
Note also that if you want to print integer value, you should use %d format specifier, %# is used for objective-c objects
It seems you are new to this platform. So here is the sample code that works -
NSMutableArray *arrayOne = [#[#"13L6-A67-1",#"13NAPUSD-A1",#"13NASUWO-X1",#"13NASUWO-X1",#"13ASECON-D1",#"13ASECON-D1",#"13ASECON-D1",#"13ASECON-D1",#"13ASMATH-C1",#"13ASMATH-C1",#"13ASMATH-C1",#"13ASMATH-C1",#"13ASPHYS-B1",#"13ASPHYS-B1",#"13ASPHYS-B1",#"13ASPHYS-B1",#"13B3ITCE-F1",#"13B3ITCE-F1",#"13B3ITCE-F1",#"13B3ITCE-F1" ] mutableCopy];
NSUInteger index = [arrayOne indexOfObject:#"13ASECON-D1"];
if (index != NSNotFound) {
[arrayOne replaceObjectAtIndex:index withObject:#"DIFFERENT_VALUE"];
NSLog(#"arrayOne after replaceObjectAtIndex = %#", arrayOne);
}
General guidelines -
watch out for compiler warning when you build.
put breakpoint and step through your code which doesn't work.
I've got a layered NSMutableDictionary object and i'd like to be able to remove dictionaries deeper down in the hierarchy. Is there a quick and easy way to do this, for example, a removeObjectAtKeyPath-like method? Can't seem to find one.
Thanks!
Nothing built in, but your basic category method will do just fine:
#implementation NSMutableDictionary (WSSNestedMutableDictionaries)
- (void)WSSRemoveObjectForKeyPath: (NSString *)keyPath
{
// Separate the key path
NSArray * keyPathElements = [keyPath componentsSeparatedByString:#"."];
// Drop the last element and rejoin the path
NSUInteger numElements = [keyPathElements count];
NSString * keyPathHead = [[keyPathElements subarrayWithRange:(NSRange){0, numElements - 1}] componentsJoinedByString:#"."];
// Get the mutable dictionary represented by the path minus that last element
NSMutableDictionary * tailContainer = [self valueForKeyPath:keyPathHead];
// Remove the object represented by the last element
[tailContainer removeObjectForKey:[keyPathElements lastObject]];
}
#end
N.B. That this requires that the second-to-last element of the path -- the tailContainer be something that responds to removeObjectForKey:, probably another NSMutableDictionary. If it's not, boom!
You can create a category :
This is upto 1 level down:
#import "NSMutableDictionary+RemoveAtKeyPath.h"
#implementation NSMutableDictionary (RemoveAtKeyPath)
-(void)removeObjectAtKeyPath:(NSString *)keyPath{
NSArray *paths=[keyPath componentsSeparatedByString:#"."];
[[self objectForKey:paths[0]] removeObjectForKey:paths[1]];
}
#end
It is called as :
NSMutableDictionary *adict=[[NSMutableDictionary alloc]initWithDictionary:#{#"key1" : #"obj1", #"key11":#"obj11"}];
NSMutableDictionary *bdict=[[NSMutableDictionary alloc]initWithDictionary:#{#"key2" : adict}];
NSLog(#"%#",bdict);
NSLog(#"%#",[bdict valueForKeyPath:#"key2.key1"]);
[bdict removeObjectAtKeyPath:#"key2.key1"];
NSLog(#"After category : %#",bdict);
Minor improvement to Josh's answer, in order to handle keypaths which don't contain a period (i.e. keypaths which are actually keys):
- (void)removeObjectAtKeyPath:(NSString *)keyPath
{
NSArray *keyPathElements = [keyPath componentsSeparatedByString:#"."];
NSUInteger numElements = [keyPathElements count];
if (numElements == 1) {
[self removeObjectForKey:keyPath];
} else {
NSString *keyPathHead = [[keyPathElements subarrayWithRange:(NSRange){0, numElements - 1}] componentsJoinedByString:#"."];
NSMutableDictionary *tailContainer = [self valueForKeyPath:keyPathHead];
[tailContainer removeObjectForKey:[keyPathElements lastObject]];
}
}
I know this is an older post, but I needed to find the same solution in Swift 2.0, unable to find a simple answer I came up with this solution:
public extension NSMutableDictionary {
public func removeObjectAtKeyPath(keyPath:String) {
let elements = keyPath.componentsSeparatedByString(".")
let head = elements.first!
if elements.count > 1 {
let tail = elements[1...elements.count-1].joinWithSeparator(".")
if let d = valueForKeyPath(head) as? NSMutableDictionary {
d.removeObjectAtKeyPath(tail)
}
}else{
removeObjectForKey(keyPath)
}
}
}
I've added an extension to NSMutableDictionary using recursion to step thru the keyPath
I just iterate on jscs's accepted answer with minor improvement - working on the KVC key-path using NSString's built-in pathUtlities category.
#implementation NSMutableDictionary (NestedMutableDictionaries)
- (void)removeObjectForKeyPath: (NSString *)keyPath
{
NSArray *key = [keyPath pathExtension];
NSString *keyPathHead = [keyPath stringByDeletingPathExtension];
[[self valueForKeyPath:keyPathHead] removeObjectForKey:key];
}
#end
Just a little nicer, I think.
Part of this assignment includes printing out on the display the current equation that is present to be solved, for that I use the following methods:
+ (NSString *)descriptionOfTopOfStack:(NSMutableArray *)stack {
NSMutableString *programFragment = [NSMutableString stringWithString:#""];
id topOfStack = [stack lastObject];
if (topOfStack) [stack removeLastObject];
if ([topOfStack isKindOfClass:[NSNumber class]]) {
[programFragment appendFormat:#"%g", [topOfStack doubleValue]];
} else if ([topOfStack isKindOfClass:[NSString class]]) {
NSString *operation = topOfStack;
if ([self isDoubleOperandOperation:operation]) {
[programFragment appendFormat:#"(%# %# %#)", [self descriptionOfTopOfStack:stack], operation, [self descriptionOfTopOfStack:stack]];
} else if ([self isSingleOperandOperation:operation]) {
[programFragment appendFormat:#"%#( %# )", operation, [self descriptionOfTopOfStack:stack]];
} else if ([ self isNoOperandOperation:operation]) {
[programFragment appendFormat:#"%#", operation];
} else if ([self isVariable:operation]) {
[programFragment appendFormat:#"%#", operation];
}
}
return programFragment;
}
+ (NSString *)descriptionOfProgram:(id)program {
NSMutableArray *stack;
if ([program isKindOfClass:[NSArray class]]) {
stack = [program mutableCopy];
}
return [self descriptionOfTopOfStack:stack];
}
My program computes the results and everything just fine, the only problem is that when I enter a variable, digit or single operand operation the display only shows said last entry, because it doesn't continue to iterate over the rest of the values present in the array, because no other recursive calls are made, any idea how I can make the program execute throughout the entire stack and not have it break the output?
I am not quite sure what you mean. The recursion should stop at a variable, digit or single operand operation. Although for a sin(operand) operation it should continue with the operand.
Did you take into account that your stack might be not completely defined?
Say you enter: 3 Enter 5 + 6 Enter 7 * 9 sqrt
this should translate to: 3+5, 6, sqrt(7*9)
So you have three elements still on your stack, but your approach stopped at sqrt(7*9).
You need to add a check at the to see if there is anything left on the stack, and continue if necessary (and add the comma's).
OK, another hint then (to be added at the end):
if ([stack count]) { // did I finish the entire stack?
[programFragment appendFormat:#"%#, %#", [self describeStack:stack], programFragment];
}
Interestingly you have used a NSMutableString, I did it with a NSString and used the class method stringWithFormat. So each time my result is a new string. I do not know if either approach is better.
aleene already answered, but just to clarify. I added the [stack count] check in the method that calls the recursive function.
+ (NSString *)descriptionOfProgram:(id)program {
NSMutableArray *stack;
NSString *strDesc = #"";
if ([program isKindOfClass:[NSArray class]]) {
// Make a consumable, mutable copy:
stack = [program mutableCopy];
}
while (stack.count) {
strDesc = [strDesc stringByAppendingString:[self descriptionOfTopOfStack:stack]];
if (stack.count) {
// More statements still on stack. We will loop again, but first, append comma separator:
strDesc = [strDesc stringByAppendingString:#", "];
}
}
return strDesc;
}