web-dev-qa-db-ja.com

NSMutableArrayを使用した2D配列

Objective-Cで可変の2次元配列を作成する必要があります。

たとえば、私は持っています:

NSMutableArray *sections;
NSMutableArray *rows;

sectionsの各アイテムは、配列rowsで構成されます。 rowsは、オブジェクトを含む配列です。

そして、私はこのような何かをしたい:

[ sections[i] addObject: objectToAdd]; //I want to add a new row

順序は次のようになります:セクション0、行:obj1、obj2、obj3セクション1、行:obj4、obj5、obj6、obj 7 ...

Objective-Cでそれを行う方法はありますか?

43

まず、使用前にオブジェクトを割り当てて初期化する必要があります。次のようなものです。NSMutableArray * sections = [[NSMutableArray alloc] initWithCapacity:10];行には、単一のNSMutableArray * rows;ではなく、それぞれに1つのオブジェクトが必要です

第二に、Xcode 4.4+(添え字を導入したsection[i]section[i] = …)を使用しているかどうかによって、読み取りに[sections objectAtIndex:i]を使用し、書き込みに[section replaceObjectAtIndex:i withObject: objectToAdd]を使用する必要がある場合があります。

3番目に、配列には穴、つまりobj1、nil、obj2を含めることはできません。すべてのインデックスに実際のオブジェクトを提供する必要があります。何も置く必要がない場合は、 NSNull objectを使用できます。

さらに、Objective-CオブジェクトをプレーンなC配列に保存できることも忘れないでください。

id table[lnum][rnum];
table[i][j] = myObj;
88
mouviciel

配列を使用してこれを行う場合は、sections配列を初期化し、次のように行配列を追加します。

NSMutableArray *sections = [[NSMutableArray alloc] init];
NSMutableArray *rows = [[NSMutableArray alloc] init];
//Add row objects here

//Add your rows array to the sections array
[sections addObject:rows];

この行オブジェクトを特定のインデックスに追加する場合は、次を使用します。

//Insert your rows array at index i
[sections insertObject:rows atIndex:i];

その後、配列を取得して、この行の配列を変更できます。

//Retrieve pointer to rows array at index i
NSMutableArray *rows = [sections objectAtIndex:i]
//modify rows array here

SectionというNSMutableArrayメンバーを持つrowsという独自のクラスをいつでも作成できます。次に、この配列内に行を格納し、Sectionオブジェクトを配列に格納します。

@interface Section : NSObject {
    NSMutableArray *rows;
}

次に、Sectionアイテムを作成するだけで、行アイテムを追加/削除するメソッドをクラス内に作成できます。次に、すべてのSectionsアイテムを別の配列内にパッケージ化します。

Section *aSection = [[Section alloc] init];
//add any rows to your Section instance here

NSMutableArray *sections = [[NSMutableArray alloc] init];
[sections addObject:aSection];

これは、Sectionインスタンスごとにプロパティを追加する場合に便利になります。

17
Alex Rozanski

この言語は、多次元のオブジェクト指向配列をサポートしていませんが、次のように、NSMutableArrayで満たされたNSMutableArrayを使用してそれを行うクラスを作成できます。私はこれまたは何もコンパイルしようとしませんでした、私はちょうどそれを入力しました。

@interface SectionArray : NSObject {
  NSMutableArray *sections;
}
- initWithSections:(NSUInteger)s rows:(NSUInteger)r;
+ sectionArrayWithSections:(NSUInteger)s rows:(NSUInteger)r;
- objectInSection:(NSUInteger)s row:(NSUInteger)r;
- (void)setObject:o inSection:(NSUInteger)s row:(NSUInteger)r;
@end
@implementation SectionArray
- initWithSections:(NSUInteger)s rows:(NSUInteger)r {
  if ((self = [self init])) {
    sections = [[NSMutableArray alloc] initWithCapacity:s];
    NSUInteger i;
    for (i=0; i<s; i++) {
      NSMutableArray *a = [NSMutableArray arrayWithCapacity:r];
      for (j=0; j<r; j++) {
        [a setObject:[NSNull null] atIndex:j];
      }
      [sections addObject:a];
    }
  }
  return self;
}
+ sectionArrayWithSections:(NSUInteger)s rows:(NSUInteger)r {
  return [[[self alloc] initWithSections:s rows:r] autorelease];
}
- objectInSection:(NSUInteger)s row:(NSUInteger)r {
  return [[sections objectAtIndex:s] objectAtIndex:r];
}
- (void)setObject:o inSection:(NSUInteger)s row:(NSUInteger)r {
  [[sections objectAtIndex:s] replaceObjectAtIndex:r withObject:0];
}
@end

次のように使用します。

SectionArray *a = [SectionArray arrayWithSections:10 rows:5];
[a setObject:@"something" inSection:4 row:3];
id sameOldSomething = [s objectInSection:4 row:3];
9
Jack Nutting

なんてこったい。この質問を復活させている限り、文字通りのコレクション構文と視覚的なフォーマット解釈の時代の何かがここにあります!

誰かが疑問に思っている場合、これは動作します:

NSMutableArray *multi = [@[ [@[] mutableCopy] , [@[] mutableCopy] ] mutableCopy];
multi[1][0] = @"Hi ";
multi[1][1] = @"There ";
multi[0][0] = @"Oh ";
multi[0][1] = @"James!";        
NSLog(@"%@%@%@%@", multi[0][0], multi[1][0], multi[1][1], multi[0][1]);

結果:「ああ、ジェームズ!」

もちろん、multi[3][5] = @"?"のようなものを試して無効なインデックス例外を取得するという問題があるため、NSMutableArrayのカテゴリを作成しました。

@interface NSMutableArray (NullInit)
+(NSMutableArray *)mutableNullArrayWithSize:(NSUInteger)size;
+(NSMutableArray *)mutableNullArraysWithVisualFormat:(NSString *)string;
@end

@implementation NSMutableArray (NullInit)

+(NSMutableArray *)mutableNullArrayWithSize:(NSUInteger)size
{
    NSMutableArray *returnArray = [[NSMutableArray alloc] initWithCapacity:size];
    for (int i = 0; i < size; i++) {
        [returnArray addObject:[NSNull null]];
    }
    return returnArray;
}

+(NSMutableArray *)mutableNullArraysWithVisualFormat:(NSString *)string
{
    NSMutableArray *returnArray = nil;
    NSRange bitRange;
    if ((bitRange = [string rangeOfString:@"^\\[\\d+]" options:NSRegularExpressionSearch]).location != NSNotFound) {
        NSUInteger size = [[string substringWithRange:NSMakeRange(1, bitRange.length - 2)] integerValue];
        if (string.length == bitRange.length) {
            returnArray = [self mutableNullArrayWithSize:size];
        } else {
            returnArray = [[NSMutableArray alloc] initWithCapacity:size];
            NSString *nextLevel = [string substringWithRange:NSMakeRange(bitRange.length, string.length - bitRange.length)];
            NSMutableArray *subArray;
            for (int i = 0; i < size; i++) {
                subArray = [self mutableNullArraysWithVisualFormat:nextLevel];
                if (subArray) {
                    [returnArray addObject:subArray];
                } else {
                    return nil;
                }
            }
        }
    } else {
        return nil;
    }
    return returnArray;
}

@end

ご覧のとおり、配列をNSNullでいっぱいにする便利なメソッドがあるので、ワイルド放棄でインデックスを設定できます。

第二に、[3][12](3 x 12配列)のような視覚形式で文字列を解析する再帰的なメソッドがあります。文字列が何らかの方法で無効な場合、メソッドはnilを返しますが、有効な場合は、指定したサイズの多次元配列全体を取得します。

ここではいくつかの例を示します。

NSMutableArray *shrub = [NSMutableArray mutableNullArrayWithSize:5];
NSMutableArray *tree = [NSMutableArray mutableNullArraysWithVisualFormat:@"[3][12]"]; // 2-Dimensional Array
NSMutableArray *threeDeeTree = [NSMutableArray mutableNullArraysWithVisualFormat:@"[3][5][6]"]; // 3-Dimensional Array
NSMutableArray *stuntedTree = [NSMutableArray mutableNullArraysWithVisualFormat:@"[6][4][k]"]; // Returns nil

ビジュアルフォーマットメソッドに好きなだけディメンションを渡し、次のようにリテラル構文でディメンションにアクセスできます。

NSMutableArray *deepTree = [NSMutableArray mutableNullArraysWithVisualFormat:@"[5][3][4][2][7]"];
deepTree[3][2][1][0][5] = @"Leaf";
NSLog(@"Look what's at 3.2.1.0.5: %@", deepTree[3][2][1][0][5]);

とにかく、これは何よりも運動として行いました。それはおそらく、物事の壮大なスキームではかなり効率的です... Objective-Cオブジェクトポインタの多次元配列をどのように作成していると考えてください。

6
Matt Mc

ジャックのコードのおかげで、私は少しそれに取り組みました。私は私のプロジェクトの1つの文字列のための多次元nsmutablearrayが必要です、それはまだ修正する必要があるものがありますが、現時点では文字列だけが動作します、私はここに投稿します、私は提案のために開いています現在、Objective Cで...

@interface SectionArray : NSObject {

  NSMutableArray *sections;    

}
- initWithSections:(NSUInteger)intSections:(NSUInteger)intRow;
+ sectionArrayWithSections:(NSUInteger)intSections:(NSUInteger)intRows;
- objectInSection:(NSUInteger)intSection:(NSUInteger)intRow;
- (void)setObject:(NSString *)object:(NSUInteger)intSection:(NSUInteger)intRow;
@end

@implementation SectionArray

- initWithSections:(NSUInteger)intSections:(NSUInteger)intRow {
    NSUInteger i;
    NSUInteger j;

    if ((self = [self init])) {
        sections = [[NSMutableArray alloc] initWithCapacity:intSections];
        for (i=0; i < intSections; i++) {
            NSMutableArray *a = [NSMutableArray arrayWithCapacity:intRow];
            for (j=0; j < intRow; j++) {
                [a insertObject:[NSNull null] atIndex:j];
            }
            [sections addObject:a];
        }
    }
    return self;    
}
- (void)setObject:(NSString *)object:(NSUInteger)intSection:(NSUInteger)intRow {
    [[sections objectAtIndex:intSection] replaceObjectAtIndex:intRow withObject:object];
}
- objectInSection:(NSUInteger)intSection:(NSUInteger)intRow {
    return [[sections objectAtIndex:intSection] objectAtIndex:intRow];
}
+ sectionArrayWithSections:(NSUInteger)intSections:(NSUInteger)intRows {
    return [[self alloc] initWithSections:intSections:intRows] ;
}
@end

これは正常に動作しています!!!

私は現在このように使用しています

SectionArray *secA = [[SectionArray alloc] initWithSections:2:2];
[secA setObject:@"Object":0:0];
[secA setObject:@"ObjectTwo":0:1];
[secA setObject:@"ObjectThree":1:0];
[secA setObject:@"ObjectFour":1:1];

NSString *str = [secA objectInSection:1:1];

NSLog(@" object is = %@" , str);

ジャックありがとう!

5
REDXD88

古いスレッドを復活させましたが、私はジャックのコードを作り直しました。1。コンパイルし、2。2D c配列[rows] [columns]の順序で、[sections(columns)] [rows]があります。どうぞ!

TwoDArray.h:

#import <Foundation/Foundation.h>

@interface TwoDArray : NSObject

@property NSMutableArray *rows;

- initWithRows:(NSUInteger)rows columns:(NSUInteger)columns;
+ sectionArrayWithRows:(NSUInteger)rows columns:(NSUInteger)columns;
- objectInRow:(NSUInteger)row column:(NSUInteger)column;
- (void)setObject:(id)obj inRow:(NSUInteger)row column:(NSUInteger)column;

@end

TwoDArray.m:

#import "TwoDArray.h"

@implementation TwoDArray

- (id)initWithRows:(NSUInteger)rows columns:(NSUInteger)columns {
    if ((self = [self init])) {
        self.rows = [[NSMutableArray alloc] initWithCapacity: rows];
        for (int i = 0; i < rows; i++) {
            NSMutableArray *column = [NSMutableArray arrayWithCapacity:columns];
            for (int j = 0; j < columns; j++) {
                [column setObject:[NSNull null] atIndexedSubscript:j];
            }
            [self.rows addObject:column];
        }
    }
    return self;
}
+ (id)sectionArrayWithRows:(NSUInteger)rows columns:(NSUInteger)columns {
    return [[self alloc] initWithRows:rows columns:columns];
}
- (id)objectInRow:(NSUInteger)row column:(NSUInteger)column {
    return [[self.rows objectAtIndex:row] objectAtIndex:column];
}
- (void)setObject:(id)obj inRow:(NSUInteger)row column:(NSUInteger)column {
    [[self.rows objectAtIndex:row] replaceObjectAtIndex:column withObject:obj];
}
@end
0
Matt Cooper

参考:Jackのコードは、機能する前に多くの作業が必要です。他の問題の中でも特に、自動解放により、データにアクセスする前にデータが解放され、その使用法が実際にsectionArrayWithSections:rowsとして定義されているときにクラスメソッドarrayWithSections:rows:を呼び出します。

機会があれば、後で実際の作業コードを投稿しようとするかもしれません。

0
dejo