How to remove elements of NSDictionary - objective-c

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"]; }
}

Related

Objective C. NSMutable Dictionary adding value to existing key

Is there any way to add a value to an existing key on a NSMutableDictionary?
Here is snippet of my code
NSMutableArray *mainFeedList = [NSMutableArray array];
[mainFeedList addObjectsFromArray:feedList];
for(int i = 0; i < mainFeedList.count; i++){
NSMutableArray *allFeed = [NSMutableArray array];
NSString *categoryId = [mainFeedList[i] valueForKey: #"categoryId"];
[allFeed addObject:mainFeedList[i]];
if(allFeed != nil && allFeed.count > 0) {
[feedContent setObject:allFeed
forKey:[combinedCategories[(int)[categoryId integerValue]] valueForKey: #"name"]];
}
Sample scenario:
NSMutableDictionary *mDict = #{#"key1":#"value1",#"key2": #"value2"};
I know that
[mDict setObject:mArray forKey:#"key1"];
will set an object to key1 but what I need is
add another object to key1 without replacing existing object (i need it both)
A structure of any NSDictionary is "one key to one object". If you would like to build a structure which maps one key multiple objects, you need an NSDictionary that maps keys to collections, such as NSArray or NSMutableArray:
NSMutableDictionary *mDict = #{
#"key1": [#[ #"value1" ] mutableCopy]
, #"key2": [#[ #"value2" ] mutableCopy]
};
Now you can add values to keys without replacing the existing ones:
[mDict[#"key1"] addObject:#"value3"];
NSDictionary only allows a single object corresponding to a single key. If you would like to add multiple objects corresponding to a single key, if you have string type of object then you can use separators also to combine strings like:
[mDict setObject:[NSString stringWithFormat:#"%#,%#", [mDict objectforKey:#"key1"], #"value2"] forKey:#"key1"];
Otherwise, you have to take collections, which you have already defined in your question.
add another object to key1 without replacing existing object...
why not set an dict to key1?
before:
[dict setObject:#"a" forKey:#"key1"];
U wanna:
add #"b" to "key1", in dict;
why not like:
[dict setObject:#{#"a":#"subKey1", #"b":#"subKey2"} forKey:#"key1"];
I would suggest storing an array as a key in your dictionary like I do below :
// Setting the value for "key1" to an array holding your first value
NSMutableDictionary *mDict = #{#"key1":#["value1"],#"key2": #"value2"};
Now when I want to add a new value I would do this:
// Create temp array
NSMutableArray *temp = mDict[#"key1"];
// Add new object
[temp addObject:#"value3"];
// Convert temp NSMutableArray to an NSArray so you can store it in your dict
NSArray *newArray = [[NSArray alloc] initWithArray:temp];
// Replace old array stored in dict with new array
mDict[#"key1"] = newArray;
Furthermore, if you are not sure if an array is already stored for that key you can run a check and populate with an empty dictionary like below:
if (mDict[#"key1"] == nil) {
mDict[#"key1"] = #[];
}

Flatten an NSArray

I have an array like this:
array: (
(
"http://aaa/product/8_1371121323.png",
"http://aaa/product/14_1371123271.png"
),
(
"http://aaa/product/9_1371121377.png"
)
)
and I have to create another array from that one like this
array: (
"http://aaa/product/8_1371121323.png",
"http://aaa/product/14_1371123271.png",
"http://aaa/product/9_1371121377.png"
)
How can I do that? Is it possible to combine all the objects and separate them using some string?
It can be done in a single line if you like key-value coding (KVC). The #unionOfArrays collection operator does exactly what you are looking for.
You may have encountered KVC before in predicates, bindings and similar places, but it can also be called in normal Objective-C code like this:
NSArray *flatArray = [array valueForKeyPath: #"#unionOfArrays.self"];
There are other collection operators in KVC, all prefixed with an # sign, as discussed here.
Sample Code :
NSMutableArray *mainArray = [[NSMutableArray alloc] init];
for (int i = 0; i < bigArray.count ; i++)
{
[mainArray addObjectsFromArray:[bigArray objectAtIndex:i]];
}
NSLog(#"mainArray :: %#",mainArray);
Sample code:
NSArray* arrays = #(#(#"http://aaa/product/8_1371121323.png",#"http://aaa/product/14_1371123271.png"),#(#"http://aaa/product/9_1371121377.png"));
NSMutableArray* flatArray = [NSMutableArray array];
for (NSArray* innerArray in arrays) {
[flatArray addObjectsFromArray:innerArray];
}
NSLog(#"%#",[flatArray componentsJoinedByString:#","]);
NSMutableArray *arr1 = [NSMutableArray arrayWithArray:[initialArray objectAtIndex:0]];
[arr1 addObjectsFromArray:[initialArray objectAtIndex:1]];
Now arr1 contains all the objects

Create Instance variables at runtime

I want to create instance variables dynamically at runtime, and I want to add these variables to a category. The number of the instance variables may change based on the configuration/properties file which I am using for defining them.
Any ideas??
Use Associative References - this is tricky, but that is the mechanism invented specifically for your use case.
Here is an example from the link above: first, you define a reference and add it to your object using objc_setAssociatedObject; then you can retrieve the value back by calling objc_getAssociatedObject.
static char overviewKey;
NSArray *array = [[NSArray alloc] initWithObjects:# "One", #"Two", #"Three", nil];
NSString *overview = [[NSString alloc] initWithFormat:#"%#", #"First three numbers"];
objc_setAssociatedObject (
array,
&overviewKey,
overview,
OBJC_ASSOCIATION_RETAIN
);
[overview release];
NSString *associatedObject = (NSString *) objc_getAssociatedObject (array, &overviewKey);
NSLog(#"associatedObject: %#", associatedObject);
objc_setAssociatedObject (
array,
&overviewKey,
nil,
OBJC_ASSOCIATION_ASSIGN
);
[array release];
I'd be inclined to just use a NSMutableDictionary (see NSMutableDictionary Class Reference). Thus, you would have an ivar:
NSMutableDictionary *dictionary;
You'd then initialize it:
dictionary = [NSMutableDictionary dictionary];
You can then save values to it dynamically in code, e.g.:
dictionary[#"name"] = #"Rob";
dictionary[#"age"] = #29;
// etc.
Or, if you are reading from a file and don't know what the names of the keys are going to be, you can do this programmatically, e.g.:
NSString *key = ... // your app will read the name of the field from the text file
id value = ... // your app will read the value of the field from the text file
dictionary[key] = value; // this saves that value for that key in the dictionary
And if you're using an older version of Xcode (before 4.5), the syntax is:
[dictionary setObject:value forKey:key];
Depends on exactly what you want to do, the question is vague but if you want to have several objects or several integers or so on, arrays are the way to go. Say you have a plist with a list of 100 numbers. You can do something sort of like this:
NSArray * array = [NSArray arrayWithContentsOfFile:filePath];
// filePath is the path to the plist file with all of the numbers stored in it as an array
That will give you an array of NSNumbers, you can then turn that into an array of just ints if you want like this;
int intArray [[array count]];
for (int i = 0; i < [array count]; i++) {
intArray[i] = [((NSNumber *)[array objectAtIndex:i]) intValue];
}
Whenever you want to get an integer from a certain position, lets say you want to look at the 5th integer, you would do this:
int myNewInt = intArray[4];
// intArray[0] is the first position so [4] would be the fifth
Just look into using a plist for pulling data, it will them be really easy to create arrays of custom objects or variables in your code by parsing the plist.

Merge two NSArrays consisting of dictionaries, based on a parameter in dictionaries

I have a NSMutableArray and a NSArray. Both consist of elements that are NSDictionarys themselves.
A sample structure of both is as follows:
NSMutableArray
[
{
objectId = 4274;
name = orange;
price = 45;
status = approved;
},
{
objectId = 9035;
name = apple;
price = 56;
status = approved;
},
{
objectId = 7336;
name = banana;
price = 48;
status = approved;
}
.
.
.
.
]
and NSAraay is
NSArray
[
{
objectId = 4274;
name = orange;
price = 106;
status = not_approved;
},
{
objectId = 5503;
name = apple;
price = 56;
status = approved;
}
]
What I want is to merge these two arrays so that, if any element in NSArray has same objectId as any element in NSMutableArray, element in NSArray should overwrite on element in NSMutableArray.
So in this case final merged array should look like this
MergedArray
[
{
objectId = 4274;
name = orange;
price = 106;
status = not_approved;
},
{
objectId = 9035;
name = apple;
price = 56;
status = approved;
},
{
objectId = 7336;
name = banana;
price = 48;
status = approved;
},
{
objectId = 5503;
name = apple;
price = 56;
status = approved;
}
.
.
.
.
]
Only way to this I know is to iterate through both arrays and merge. Is there any better way? Any help will be greatly appreciated.
EDIT:
Following dasblinkenlights suggestion, I did it following way
-(NSMutableArray*)mergeTwoArray:(NSArray*)array1 :(NSArray*)array2
{
//array1 will overwrite on array2
NSSet* parentSet = [NSSet setWithArray:array2];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (NSDictionary *item in parentSet)
[dict setObject: item forKey: [item objectForKey:#"objectId"]];
NSLog(#"initial dictionary is %#",dict);
for (NSDictionary *item in array1)
[dict setObject: item forKey: [item objectForKey:#"objectId"]];
NSLog(#"final dictionary is %# with all values %#", dict,[dict allValues]);
return [NSMutableArray arrayWithArray:[dict allValues]];
}
Since your objectId value can be used as a unique key, you could potentially create an NSMutableDictionary on the side, populate it with NSDictionary objects from the first array using objectId value as the key, go through the second array, do the overwrites, and finally harvest the values of the resultant NSMutableDictionary into your final output.
Note that this approach might be helpful only if your arrays are relatively long (1000+ items). If you deal with 10..100 items, I wouldn't bother, and code two nested loops as you suggested.
I would recommend iterating through both arrays and merging, but first sort them. Once sorted, you can merge two arrays in O(N) time. For most purposes, this is about as fast as you can get, and it requires very little code.
If they are large enough that the sort is a bottleneck, you could get fancy using an NSSet: put the (elements of the) over-riding array in the set first, and then add the elements of the original array. But you would have to implement an isEqual method for your elements. In this case, it would mean that your elements would no longer be NSDictionary, but rather a class that inherits from NSDictionary but implements the isEqual method to compare the object ID fields.
Because NSSet gives amortized constant time access, this would be faster, if the arrays are large, since there is no sort phase.

NSArray from array in NSDictionary

I have a NSDictionary loaded from a remote PList.
It contains an array of dictionaries:
(
{
id = "1234";
count = "45";
},
{
id = "244";
count = "89";
},
{
id = "9909";
count = "123";
}
)
How do I get this into an NSArray? I don't want separate arrays for each key.
I just want an NSArray of NSDictionary.
There is probably a simple answer, but this has been bugging me.
Thanks
You say you have a dictionary containing the array. Whatever the key for the array is, just ask do [dictionary objectForKey:theKey], and you'll have the array.
EDIT: From your comments, it sounds like you just have an NSArray which is not in an NSDictionary at all. If so, you already have what you are looking for.
How about:
NSArray *dicts = [NSPropertyListSerialization propertyListWithData:data
options:0
format:NSPropertyListOpenStepFormat
error:NULL];
Note that this is a deprecated plist format (XML or binary format is now preferred).
have u tried [dictionary objectAtIndex:0]objectAtIndex:0]. try iterating over objectAtIndex in the outer loop.
all the best.