I have a NSMutable array which i am storing some initial numbers. What I want to do is to be able to look at the numbers, and for some situations, remove that item and replace it with two more.
My insert/replace code seems to work when index > 0, however, when I try to insertObject AtIndex:0, it doesnt insert anything at 0, but places a null object at the end of the array.
To show the insert issue I can create an empty iOS Application.
I create the NSMutableArray as a property on the ViewController:
#property (strong) NSMutableArray *testArray;
And then in the implementation:
self.testArray = [[NSMutableArray alloc] init];
[self.testArray addObject: [NSNumber numberWithInteger:1]];
[self.testArray addObject: [NSNumber numberWithInteger:2]];
[self.testArray insertObject:[NSNumber numberWithInteger:3] atIndex:0];
If i place a break point after the insert, the debugger shows:
[0] = (id) 0x07123180 (int) 1
[1] = (id) 0x07614210 (int) 2
[2] = (id) 0x00000000
Where I was expecting to see an (int) 3 at place 0.
If I set atIndex:1, I get this:
[0] = (id) 0x07123180 (int) 1
[1] = (id) 0x07131fb0 (int) 3
[2] = (id) 0x07614210 (int) 2
Which is correct.
Why is index = 0 not working?
Works for me:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSMutableArray *testArray = [[NSMutableArray alloc] init];
[testArray addObject: [NSNumber numberWithInteger:1]];
[testArray addObject: [NSNumber numberWithInteger:2]];
[testArray insertObject:[NSNumber numberWithInteger:3] atIndex:0];
for (NSNumber *num in testArray)
NSLog(#"%#", num);
}
return 0;
}
2013-09-15 09:51:18.266 ArrayTest[890:303] 3
2013-09-15 09:51:18.269 ArrayTest[890:303] 1
2013-09-15 09:51:18.269 ArrayTest[890:303] 2
Program ended with exit code: 0
If I break on the for statement and use lldb:
(lldb) po testArray
<__NSArrayM 0x100109120>(
3,
1,
2
)
(this was using Xcode 5 DP 6 under Mavericks DP 7).
Works for me
testArray = [[NSMutableArray alloc]init];
[testArray addObject:[NSNumber numberWithInt:1]];
[testArray addObject:[NSNumber numberWithInt:2]];
[testArray insertObject:[NSNumber numberWithInt:0] atIndex:0];
NSLog(#"%#",testArray);
Log
2013-09-15 10:53:39.048 JsonExample[79141:a0b] (
0,
1,
2
)
I copied your sample code too and it works fine in Xcode 4
Related
I've read and tried a dozen or more variants of my own question, but still need some help please.
I have a large existing array, and I want to add a new object (key and value) to each record.
This is an element in the incoming array:
{
"trip_id": 65,
"arrival_time": "08:56:08",
"departure_time": "08:56:08",
"stop_id": 1161,
"stop_sequence": 8,
"stop_headsign": 0
},
This is what I want to achieve:
{
"trip_id": 65,
"arrival_time": "08:56:08",
"departure_time": "08:56:08",
"stop_id": 1161,
"stop_name": "a stop name",
"stop_sequence": 8,
"stop_headsign": 0
},
This is my code so far -- the commented lines are other attempts:
NSString *nameKey = #"stop_name";
int i=0;
for (i=0; i<stopTimesArray.count; i++) {
NSNumber *stopTimesId = [stopTimesArray[i] valueForKey:#"stop_id"];
int j=0;
for (j=0; j<stopArray.count; j++) {
NSNumber *stopId = [stopArray[j] valueForKey:#"stop_id"];
if (stopId == stopTimesId) {
NSString *stopNameString = [stopArray[j] valueForKey:#"stop_name"];
NSLog(#"stopNameString: %#", stopNameString);
[outgoingStopTimesDictionary setObject:stopNameString forKey:#"stop_name"];
//[outgoingStopTimesArray addObject:outgoingStopTimesDictionary];
//[outgoingStopTimesArray addObjectsFromArray:stopTimesArray[i]];
//[stopTimesArray[i] addObject:#{#"stop_name":stopNameString}];
//[stopTimesArray[i] addObject:#{#"stop_name":stopNameString}];
[stopTimesArray[i] addObject: outgoingStopTimesDictionary];
}
}
}
//NSLog(#"outgoingStopTimesArray: %#", outgoingStopTimesArray);
//NSLog(#"outgoingStopTimesDictionary: %#", outgoingStopTimesDictionary);
//NSLog(#"stopTimesArray: %#", stopTimesArray);
The error I am getting with approach is:
stopNameString: S Monroe Street, NB # 18th Street S, NS
[__NSCFDictionary addObject:]: unrecognized selector sent to instance 0x7fd7f2c22760
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary addObject:]: unrecognized selector sent to instance 0x7fd7f2c22760'
I'm either getting a null dictionary, or an unrecognised object exception when I try to add the dictionary to my array. Please point me to a working answer, and I'll delete my question.
It appears that your goal is to add one new key/value pair to the dictionary at stopTimesArray[i]. Here's your code all cleaned up with what I believe you need:
for (NSMutableDictionary *stopTimesDictionary in stopTimesArray) {
NSNumber *stopTimesId = stopTimesDictionary[#"stop_id"];
for (NSDictionary *stopDictionary in stopArray) {
NSNumber *stopId = stopDictionary[#"stop_id"];
if ([stopTimesId isEqual:stopId]) {
NSString *stopNameString = stopDictionary[#"stop_name"];
stopTimesDictionary[#"stop_name"] = stopNameString;
// Uncomment the following line if "stop_id" is unique within the "stopArray"
// break;
}
}
}
Since it seems your stopTimesArray contains immutable dictionaries, the above code won't work as written. Here is a solution that deals with that:
for (NSInteger i = 0; i < stopTimesArray.count; i++) {
NSDictionary *stopTimeDictionary = stopTimesArray[i];
NSNumber *stopTimesId = stopTimesDictionary[#"stop_id"];
for (NSDictionary *stopDictionary in stopArray) {
NSNumber *stopId = stopDictionary[#"stop_id"];
if ([stopTimesId isEqual:stopId]) {
NSString *stopNameString = stopDictionary[#"stop_name"];
NSMutableDictionary *tempDict = [stopTimesDictionary mutableCopy];
tempDict[#"stop_name"] = stopNameString;
[stopTimesArray replaceObjectAtIndex:i withObject:tempDict];
// Uncomment the following line if "stop_id" is unique within the "stopArray"
// break;
}
}
}
dictTo=[NSDictionary new];
dictTo =
#{
#"vPLocationLat" : [NSString stringWithFormat:#"%#",[[[[json valueForKey:#"result"] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lat"]],
#"vPLocationLong" : [NSString stringWithFormat:#"%#",[[[[json valueForKey:#"result"] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lng"]]
};
arrLocationList =[NSMutableArray new];
arrLocationList =[dictTo[#"data"] mutableCopy];
another Solution
-> Try to implement your Code as per in given Code
NSMutableArray* newArray = [NSMutableArray array];
NSArray* oldArray = outerDictionary[#"scores"];
for (NSDictionary* dictEntry in oldArray) {
NSString* leagueCode = dictEntry[#"league_code"];
if ([leagueCode isEqualToString #"epl"]) {
[newArray addObject:dictEntry];
}
}
Another one Solution
Try something like this.
Assume your array is called array and yourNewNameString is your new value for name
for(NSMutableDictionary *dict in array){
if([[dict objectForKey:#"id"]integerValue]==5){
[dict setObject:yourNewNameString forKey#"name"];
}
}
edit This is assuming you initialized your array with NSMutableDictionarys (Not just NSDictionarys)
//You can create dictionary and add it into NSMutableArray Object Like..
NSMutableArray *arr = [[NSMutableArray alloc] init];
NSDictionary *inventory = #{
#"Mercedes-Benz SLK250" : [NSNumber numberWithInt:13],
#"Mercedes-Benz E350" : [NSNumber numberWithInt:22],
#"BMW M3 Coupe" : [NSNumber numberWithInt:19],
#"BMW X6" : [NSNumber numberWithInt:16],
};
[arr addObject:inventory];
//You can access using key like...
NSString *strForBMWX6 = [[arr objectAtIndex:0] valueForKey:#"BMW X6"];
// in your case you just miss objectAtIndex:j
First, thanks #rmaddy.
I modified his answer a bit, but his was basically correct.
My final code looks like this:
for (NSInteger i = 0; i < stopTimesArray.count; i++) {
NSDictionary *stopTimesDictionary = stopTimesArray[i];
NSNumber *stopTimesId = stopTimesDictionary[#"stop_id"];
for (NSDictionary *stopDictionary in stopArray) {
NSNumber *stopId = stopDictionary[#"stop_id"];
if ([stopTimesId isEqual:stopId]) {
NSString *stopNameString = stopDictionary[#"stop_name"];
NSMutableDictionary *tempDict = [stopTimesDictionary mutableCopy];
tempDict[#"stop_name"] = stopNameString;
[outgoingStopTimesArray addObject:tempDict];
break;
}
}
}
I would like to know what's the best or most appropriate approach for this question: Given a list of numbers example [2, 3, 4, 2, 3], return the first number that occurs only once in the list.
I have followed some algorithms approach and came up with this, but not sure if there are any built-in helper functions in Objective-C that will allow me to do this with a better performance..
If there are not built-ins solutions, is there is any improvements that can be made to my approach or any other solution that could be better in terms of performance?
This is my updated solution for this:
For testing:
#import "NSArray+Addons.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray<NSNumber *> *array = #[#(2), #(7), #(3), #(2), #(3), #(2), #(7), #(3), #(2), #(3), #(4), #(7), #(5), #(5), #(9)];
NSLog(#"Unique number: %#", [array firstUniqueNumber]);
}
#end
NSArray category:
#import "NSArray+Addons.h"
#import "NSMutableDictionary+Addons.h"
#implementation NSArray (Addons)
- (NSNumber *)firstUniqueNumber
{
if (!self.count)
{
return nil;
}
NSMutableDictionary<NSNumber *, NSNumber *> *myUniqueNumbers = [[NSMutableDictionary alloc] init];
return [myUniqueNumbers uniqueValueFromArray:self];
}
#end
NSMutableDictionary category:
#import "NSMutableDictionary+Addons.h"
#implementation NSMutableDictionary (Addons)
- (NSNumber *)uniqueValueFromArray:(NSArray<NSNumber *> *)array
{
if (!array.count)
{
return nil;
}
for (NSNumber *number in array)
{
if (!self[number])
{
self[number] = [NSNumber numberWithInteger:1];
}
else
{
NSInteger count = [self[number] integerValue];
count++;
self[number] = [NSNumber numberWithInteger:count];
}
}
return [self uniqueNumberWithArray:array];
}
- (NSNumber *)uniqueNumberWithArray:(NSArray<NSNumber *> *)array
{
if (!array.count)
{
return nil;
}
NSNumber *uniqueNumber = nil;
for (NSInteger index = array.count - 1; index > 0; index--)
{
NSNumber *key = array[index];
if (self[key] && [self[key] integerValue] == 1)
{
uniqueNumber = key;
}
}
return uniqueNumber;
}
#end
NSCountedSet* set = [[NSCountedSet alloc] initWithArray:array];
NSUInteger index = [array indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
return [set countForObject:obj] == 1;
}];
return index == NSNotFound ? nil : [array objectAtIndex:index];
This problem can be reduced to element distinctness problem, so there is no linear time solution, without using hashing and extra space.
One simple solution in O(n) time on average + space is:
Build a hash based histogram of the data, that maps each value to the number of its occurances.
Find the first number in the array that its value in the histogram is 1.
Pseudo code:
map = new hashmap
for each element x:
if map contains x is a key:
map.put(x,map.get(x)+1)
else:
map.put(x,1)
for each element x in array:
if map.get(x) == 1:
return x
//if reached here - no distinct element
Example:
array = [2, 3, 4, 2, 3]
create histogram: {[2=2] [3=2], [4=1]}
iterate the array:
check 2, it has value of 2 in histogram. continue
check 3, it has value of 2 in histogram. continue
check 4, it has value of 1 in histogram. Return it and finish.
-(NSNumber *)returnFirstUniqueFromArray: (NSArray *)array{
//put the numbers in a set
NSCountedSet *numbers = [[NSCountedSet alloc] initWithArray:array];
for(NSNumber *number in array){
//if it only occurs once return
if([numbers countForObject:number]==1) return number;
}
return nil;
}
They key being here you need a good way to keep track of how many times something occurs so take advantage of NSCountedSet's "count" method. Will tell you how many times an object occurs.
I am new at iOS Dev. I want to save two different arrays (array1 & array2) in 2 dimensional array. I know how to save data directly in two dimensional array but can't by save two different arrays in one.
NSString* path = [[NSBundle mainBundle] pathForResource:#"Aasvogel" ofType:#"txt"];
NSString* content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
NSArray* foo = [content componentsSeparatedByString: #","];
NSMutableArray *array1 = #[], *array2 = #[];
for ( int i = 0; i < [foo count]; i++ )
{
NSString* day = foo[i];
if ( i % 2 == 0 ) { [array1 addObject:day];}
else { [array2 addObject:day];}
}
// and here i have populated two arrays (array1 and array2)
// Now i want to save these arraya in below two dimensional array (dataArray) atIndex:0 and at Index:1
NSMutableArray *dataArray = [[NSMutableArray alloc] initWithCapacity: 2];
[dataArray addObject:[NSMutableArray arrayWithObjects:#"e",
#"el",
#"ale",
#"vela",
#"gavel",nil] atIndex:0];
[dataArray addObject:[NSMutableArray arrayWithObjects:#"Represents 50 in Roman numeral",
#"Building Wing",
#"Pub Brew",
#"Thin Parchment or membranes",
#"chairperson's hammer",nil] atIndex:1];
I have recently implemented 2D array into my application. Please check below code which is available at 2DArray
int capacity;
#property (nonatomic, strong) NSMutableArray *outerArray;
#define kCRL2DArrayEmptyKey #"kCRL2DArrayEmptyKey"
- (id) initWithRows:(int)x columns:(int)y
{
if (self = [super init])
{
capacity = y;
self.outerArray = [NSMutableArray array];
for (int i = 0; i < x; i++) {
NSMutableArray *innerArray = [NSMutableArray array];
for (int j = 0; j < y; j++) {
[innerArray addObject:kCRL2DArrayEmptyKey];
}
[self.outerArray addObject:innerArray];
}
}
return self;
}
you can try this
NSArray * firstArray, *secondArray;
NSArray * mainArray= [[NSArray alloc]initWithObjects: firstArray, secondArray, nil];
I am not sure about 2-dimensional array in iOS but if I were you I would be saved the two arrays within a dictionary such as
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
[dict setvalue:yourArray forKey:#"FirstArray"];
[dict setvalue:yourSecondArray forKey:#"SecondArray"];
And Use it accordingly.
There’s no such thing as a two (or more) dimensional NSArray. If you genuinely need an n-dimensional array object in iOS or OS X, you can of course roll your own, or you could instead create an NSArray of NSArray instances (which are columns and which are rows is entirely up to you). In that case, you could e.g. add items by doing
[[outerArray objectAtIndex:0] addObject:#"Foo"];
[[outerArray objectAtIndex:1] addObject:#"Bar"];
That said, for the problem you are tackling, it looks to me as if an NSDictionary might be more appropriate, e.g. with keys #"e", #"el" and values #"Represents 50 in Roman numerals", #"Building Wing".
If your concern is that the keys of NSDictionary are not held in sorted order, you can always extract the keys as an array and sort them. Or, if the keys change regularly, you might want to use a more sophisticated approach (e.g. keeping a separate sorted array of keys and inserting them into the right place when adding to the NSDictionary).
Also, you know that in modern Objective-C you can write e.g.
#[ #"a", #"b", #"c" ]
or
#{ #"a": #1, #"b": 2 }
rather than the very verbose forms you're using above?
this is how u add anything in a 2d array i.e an Array of arrays in objective-c
NSMutableArray *array 1 = [[NSMutableArray alloc]init];
NSMutableArray *array 2;
for(int col = 0;col <5;col++){
array2 = [[NSMutableArray alloc]init];
for(int row = 0;row<5;row++){
[array2 addObject:myItems];
}
[array1 addObject:array2];
}
hope this helps
use for loop to generate 2d array from 2 different array,
follow this stracture
int i, j;
for(i = 0; i < nrows; i++)
{
for(j = 0; j < ncolumns; j++)
array[i][j] = 0;
}
}
May be it will help you
I need a method to generate 4 numbers positioned randonly in an array. This method must be able to be called several times. The code that I tried below seems to be working.. except that everytime I call it, it generates the very same numbers sequence.
At my header file:
NSMutableSet * numberSet;
NSArray * numbers;
Code file:
numberSet = [NSMutableSet setWithCapacity:4];
[self placeRandomLine];
numbers = [numberSet allObjects];
... using the generated array
[self placeRandomLine];
numbers = [numberSet allObjects];
... using the generated array
[self placeRandomLine];
numbers = [numberSet allObjects];
... using the generated array
Random Method:
-(void)placeRandomLine
{
[numberSet removeAllObjects];
while ([numberSet count] < 4 ) {
NSNumber * randomNumber = [NSNumber numberWithInt:(arc4random() % 4)];
[numberSet addObject:randomNumber];
}
}
I am sure I am missing something here..
Thanks for your help!
Use an ordered set:
NSMutableOrderedSet *numberSet = [NSMutableOrderedSet new];
int setSize = 4;
while ([numberSet count] < setSize ) {
NSNumber * randomNumber = [NSNumber numberWithInt:arc4random_uniform(setSize)];
[numberSet addObject:randomNumber];
}
NSLog output:
numberSet: {(
2,
0,
1,
3
)}
Alternatively using an array or arbitrary numbers
Create an NSMutableArray with the four integers.
Create an empty NSMutableArray.
Use arc4random_uniform() to pick one of the numbers in the first array, remove it and place it in the second array.
Repeat for all four numbers.
The second array will have the four numbers in a random order.
Example:
NSMutableArray *a0 = [#[#3, #5, #4, #8] mutableCopy];
NSMutableArray *a1 = [NSMutableArray new];
while (a0.count) {
int randomIndex = arc4random_uniform(a0.count);
NSNumber *randomValue = a0[randomIndex];
[a1 addObject:randomValue];
[a0 removeObject:randomValue];
}
NSLog(#"a1: %#", a1);
NSLog output:
a1: (
8,
5,
3,
4
)
Alternatively using an ordered set
while ([numberSet count] < 4 ) will cause the loop to run until its elements are 0,1,2,3, because the set doesn't contain repeated elements.
i am passing one one dimensional array having elements "1,2,3,4,5,6,7"
and in my code i want to convert this array into a 2-dimensional array .
The number of columns of the 2-d array will be specified by user .
say if am setting the columns value to 3
then the output 2-d array should be in the format
123
456
7
.m file of my class
-(NSMutableArray *)OneToTwoDimensionalArray:(NSMutableArray *)values :(NSInteger)columns
{
NSMutableArray * twoDimensional=[[NSMutableArray alloc]initWithCapacity:columns];
for(int i=0;i<columns;i++)
{
[twoDimensional insertObject:values atIndex:i];
}
return twoDimensional;
}
viewcontroller.m file
EPArray *arr=[[EPArray alloc]init];
int columns=4;
arr1=[[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4",#"5",#"6",#"7",nil];
NSMutableArray *finalresult=[arr OneToTwoDimensionalArray:arr1 :columns];
for(int i=0;i<columns;i++)
{
NSLog(#"%#",[finalresult objectAtIndex:i]);
}
Try this,
NSArray *array = #[#"1", #"2", #"3", #"4", #"5", #"6", #"7"];
int noOfColumns = 3;
NSMutableArray *outerArray = [[NSMutableArray alloc] init];
for (int counter = 0; counter < [array count]; counter = counter + noOfColumns) {
NSMutableArray *innerArray = [[NSMutableArray alloc] init];
for (int arrayIndex = counter; ((arrayIndex < counter + noOfColumns) && (arrayIndex < [array count])); arrayIndex++) {
[innerArray addObject:array[arrayIndex]];
}
[outerArray addObject:innerArray];
}
NSLog(#"outerArray = %#", outerArray);
Here outerArray will give the 2 dimensional array with the provided column value. The above code is readable and easy to maintain especially if you want to make some quick changes.
Output:
outerArray = (
(
1,
2,
3
),
(
4,
5,
6
),
(
7
)
)
Next to my other answer — that I would favor — I want to offer another solution, that uses more traditional C-style programming but is quite readable.
NSUInteger columnWidth = 3;
NSArray *array = #[#1, #2, #3, #4 ,#5, #6, #7];
NSMutableArray *newArray = [NSMutableArray array];
NSUInteger columnIdx = 0;
for (NSUInteger count = 0; count < [array count]; ++count) {
if (columnIdx == 0) {
[newArray addObject:[NSMutableArray array]];
}
NSMutableArray *lastArray = [newArray lastObject];
[lastArray addObject:array[count]];
columnIdx = (++columnIdx)%columnWidth;
}
newArray now contains the subarrays as required.
note, that also this solution uses the modulo operator columnIdx = (++columnIdx)%columnWidth;.
instead of this you also could write
++columnIdx;
if(columnIdx == columnWidth) columnIdx = 0;
NSUInteger columnWidth = 3;
NSArray *array = #[#1, #2, #3, #4 ,#5, #6, #7];
NSMutableArray *mArray =[NSMutableArray array];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (idx % columnWidth == 0) {
[mArray addObject:[NSMutableArray array]];
}
[[mArray objectAtIndex:[mArray count]-1] addObject:obj];
}];
mArraynow contains 3 arrays with
(
(
1,
2,
3
)
,
(
4,
5,
6
)
,
(
7
)
)
This code uses the modulo operator that finds the remainder of division of one number by another.
if (idx % 3 == 0) {
[mArray addObject:[NSMutableArray array]];
}
if there is no remainder, it must be the index 0,3,6,…. In such a case, a new array is added to the outer array. the object are always added to the last array.
Also note that using enumerateObjectsUsingBlock: should be faster than using c-style for (for(int i=0;i<columns;i++)) or even fast enumeration.
I added a second answer that uses only C-constructs rather than blocks, but I'd favor this one.
and — of course — you should consider using a category on NSArray
#interface NSArray (Columns)
-(NSArray *)arrayOfArraysWithColumnWidth:(NSUInteger)width;
#end
#implementation NSArray (Columns)
-(NSArray *)arrayOfArraysWithColumnWidth:(NSUInteger)width
{
NSAssert(width > 0, #"width need to be 1 or greater");//sanity check
NSMutableArray *mArray =[NSMutableArray array];
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (idx % width == 0) {
[mArray addObject:[NSMutableArray array]];
}
[[mArray objectAtIndex:[mArray count]-1] addObject:obj];
}];
return mArray;
}
#end
You would use it like:
NSArray *numbers = [#[#1, #2, #3, #4 ,#5, #6, #7] arrayOfArraysWithColumnWidth:3];