Câu hỏi Làm thế nào để làm mảng thưa thớt trong ca cao


Tôi có một kích thước chưa được xác định cho tập dữ liệu dựa trên các phím số nguyên duy nhất.

Tôi muốn sử dụng NSMutableArray để tra cứu nhanh vì tất cả các khóa của tôi đều dựa trên số nguyên.

Tôi muốn làm điều này.

NSMutableArray* data = [NSMutableArray array]; // just create with 0 size

sau đó mọi người sẽ bắt đầu ném dữ liệu vào tôi với các chỉ số nguyên (tất cả là duy nhất) vì vậy tôi chỉ muốn làm một cái gì đó như thế này ...

if ([data count] < index)
    [data resize:index];  // ? how do you resize

và thay đổi kích thước của mảng để tôi có thể thực hiện ...

[data insertObject:obj atIndex:index];

với tất cả các vị trí giữa kích thước cuối cùng và kích thước mới bằng 0 mà cuối cùng sẽ được điền vào sau.

Vì vậy, câu hỏi của tôi là làm cách nào để thay đổi kích thước hiện tại NSMutableArray?

Cảm ơn, Roman


8
2017-08-30 21:34


gốc




Các câu trả lời:


Có vẻ như nhu cầu của bạn sẽ được đáp ứng tốt hơn với NSMutableDictionary. Bạn sẽ cần phải quấn intvào NSNumber các đối tượng như sau:

-(void)addItem:(int)key value:(id)obj
{
    [data setObject:obj forKey:[NSNumber numberWithInt:key]];
}

-(id)getItem:(int)key
{
    return [data objectForKey:[NSNumber numberWithInt:key]];
}

Không có cách nào dễ dàng để phóng to kích thước của một NSMutableArray, vì bạn không thể có các đối tượng nil ở giữa các khe. Tuy nhiên, bạn có thể sử dụng [NSNull null] như là một 'phụ' để tạo ra sự xuất hiện của một mảng thưa thớt.


17
2017-08-30 21:39



Thời gian tra cứu bảng băm của Nitpick-bit là O(1)  iff mọi băm khóa đến một giá trị duy nhất - nghĩa là, không có xung đột băm. Nếu hai khóa băm có cùng giá trị, thì việc thực hiện cần phải giải quyết vấn đề này - một cách tiếp cận chung là chỉ sử dụng một danh sách liên kết. Việc triển khai bảng băm tốt đối phó với những chi tiết này cho bạn, giả sử bằng cách tăng số lượng các khe băm một cách linh động khi nhiều mục được thêm vào bảng sao cho các xung đột không chắc chắn về mặt thống kê. Thật an toàn để nói rằng việc triển khai tốt, chẳng hạn như NSMutableDictionary, cung cấp "thực tế O(1)"thời gian tra cứu. - johne
NSPointerArray trực tiếp hỗ trợ một mảng các đối tượng có lỗ trong đó. Nếu một giải pháp băm là mong muốn, NSMapTable có thể hỗ trợ các phím số nguyên (thông qua API dựa trên hàm). - bbum
@bbum Trong bối cảnh của câu hỏi này wrt / đến mảng thưa thớt, NSPointerArray không hỗ trợ array of objects with holes in it.. Từ insertPointer:atIndex: tài liệu cho index tranh luận - This value must be less than the count of the receiver.. NSPointerArray có hiệu quả giống với @ Jason's NSMutableArray / [NSNull null] giải pháp, ít nhất là cho các mục đích của OP- bạn chỉ cần điền các lỗ với NULLvà không [NSNull null]'S. - johne
NSPointerArray chắc chắn nhất hỗ trợ lỗ hổng. Đó là một trong những điểm viết của lớp. Bạn phải đặt số đầu tiên. Cho dù việc thực hiện nội bộ là một mảng thưa thớt hoặc một băm hoặc, vv, là một chi tiết thực hiện. - bbum
Và, trên thực tế, nó không được thực hiện như một bộ nhớ lớn ... - bbum


Sử dụng một NSPointerArray.

http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSPointerArray_Class/Introduction/Introduction.html

NSPointerArray là một bộ sưu tập có thể thay đổi   được mô hình hóa sau NSArray nhưng nó cũng có thể   giữ giá trị NULL, có thể là   chèn hoặc trích xuất (và   đóng góp vào số lượng của đối tượng).   Hơn nữa, không giống như các mảng truyền thống,   bạn có thể đặt số lượng của mảng   trực tiếp. Trong một thùng rác được thu thập   môi trường, nếu bạn chỉ định một zeroing   cấu hình bộ nhớ yếu, nếu   phần tử được thu thập nó được thay thế bằng   giá trị NULL.

Nếu bạn sử dụng từ điển như giải pháp, hãy sử dụng NSMapTable. Nó cho phép các phím số nguyên. Các giải pháp dựa trên NSMutableDictionary đề nghị có một số tiền rất lớn của chi phí liên quan đến tất cả các boxing & unboxing các phím số nguyên.


33
2017-08-31 15:02



một NSPointerArray không phải là một mảng thưa thớt, cũng như nó không hoạt động như một. Bạn vẫn phải điền vào tất cả các chỉ mục không sử dụng với NULL con trỏ. Đầu ra từ [pointerArray insertPointer:@"test" atIndex:17]; trên một cách mới được khởi tạo NSPointerArray: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSConcretePointerArray insertPointer:atIndex:]: attempt to insert pointer at index 17 beyond bounds 0' - johne
Điều đó không đúng. Bạn không gọi được -setCount: để đặt dung lượng thành kích thước đủ. - bbum
Lưu ý rằng NSPointerArray không có sẵn trong iOS. - Yang Meyer
NSPointerArrayiOS có sẵn từ 6.0 - james_womack


Như trong câu trả lời của Jason, một NSMutableDictionary dường như là cách tiếp cận tốt nhất. Nó bổ sung thêm chi phí của việc chuyển đổi các giá trị chỉ mục đến và từ NSNumbers, nhưng đây là một giao dịch không gian / thời gian cổ điển tắt.

Trong thực hiện của tôi, tôi cũng bao gồm một NSIndexSet để làm cho việc duyệt qua mảng thưa thớt đơn giản hơn rất nhiều.

Xem https://github.com/LavaSlider/DSSparseArray


1
2018-05-26 17:38





Tôi không đồng ý với câu trả lời của bbum về vấn đề này. A NSPointerArray là một mảng, không phải là mảng thưa thớt và có sự khác biệt quan trọng giữa hai mảng.

tôi mạnh mẽ khuyên bạn không nên sử dụng giải pháp bbums.

Tài liệu cho NSPointerArray có sẵn đây.

Ca cao đã có một đối tượng mảng như được định nghĩa bởi NSArray lớp học. NSPointerArray kế thừa từ NSObject, vì vậy nó không phải là một phân lớp trực tiếp của NSArray. Tuy nhiên, NSPointerArray tài liệu xác định lớp như vậy:

NSPointerArray is a mutable collection modeled after NSArray but it can also hold NULL values

Tôi sẽ đưa ra giả định tiên đề rằng định nghĩa này từ tài liệu xác nhận rằng đây là một phân lớp "hợp lý" của NSArray.

Các định nghĩa-

Mảng "chung" là: một tập hợp các mục, mỗi mục có một số chỉ mục duy nhất được liên kết với nó.

Một mảng, không có trình độ, là: Mảng "chung" trong đó các chỉ mục của các mục có các thuộc tính sau: Chỉ mục cho các mục trong mảng bắt đầu tại 0 và tăng tuần tự. Tất cả các mục trong mảng chứa số chỉ mục nhỏ hơn số mục trong mảng. Việc thêm một mục vào một mảng phải ở chỉ mục + 1 của mục cuối cùng trong mảng, hoặc một mục có thể được chèn vào giữa hai số chỉ mục mục hiện có khiến số chỉ mục của tất cả các mục tiếp theo được tăng thêm một. Một mục tại một số chỉ mục hiện có có thể được thay thế bằng một mục khác và thao tác này không thay đổi số chỉ mục của các hoạt động hiện có. Do đó, chèn và thay thế là hai hoạt động riêng biệt.

Mảng thưa thớt là: Mảng "chung" trong đó số chỉ mục của mục đầu tiên có thể bắt đầu ở bất kỳ số nào và số chỉ mục của các mục tiếp theo được thêm vào mảng không có liên quan đến hoặc hạn chế dựa trên các mục khác trong mảng. Chèn một mục vào một mảng thưa thớt không ảnh hưởng đến số chỉ mục của các mục khác trong mảng. Chèn một mục và thay thế một mục thường đồng nghĩa trong hầu hết các triển khai. Số lượng các mục trong mảng thưa thớt không có mối quan hệ với số chỉ mục của các mục trong mảng thưa thớt.

Những định nghĩa này đưa ra những dự đoán nhất định về hành vi của một mảng "hộp đen" có thể kiểm chứng được. Để đơn giản, chúng tôi sẽ tập trung vào mối quan hệ sau:

Trong một mảng, số chỉ mục của tất cả các mục trong mảng nhỏ hơn số lượng các mục trong mảng. Trong khi điều này có thể đúng với một mảng thưa thớt, nó không phải là một yêu cầu.

Trong một bình luận cho bbum, tôi đã nói như sau:

một NSPointerArray không phải là một mảng thưa thớt, cũng như nó không hoạt động như một. Bạn vẫn phải điền vào tất cả các chỉ mục không sử dụng với NULL con trỏ. Đầu ra từ [pointerArray insertPointer:@"test" atIndex:17]; trên một cách mới được khởi tạo NSPointerArray:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSConcretePointerArray insertPointer:atIndex:]: attempt to insert pointer at index 17 beyond bounds 0'

Nó được tuyên bố, mà không chứng minh, hành vi của NSPointerArray ở trên vi phạm định nghĩa của một mảng thưa thớt. Phần này của thông báo lỗi được tiết lộ: attempt to insert pointer at index 17 beyond bounds 0', đặc biệt là phần về việc phải thêm mục mới đầu tiên vào chỉ mục 0.

bbum rồi nhận xét:

Điều đó không đúng. Bạn không gọi được -setCount: để đặt dung lượng thành kích thước đủ.

Nó là không nhạy cảm để "đặt số lượng" của số lượng mục trong một mảng thưa thớt. Nếu NSPointerArray là một mảng thưa thớt, người ta hy vọng rằng sau khi thêm mục đầu tiên tại chỉ mục 17, số lượng các mục trong NSPointerArray sẽ là một. Tuy nhiên, theo lời khuyên của bbums, số lượng mục trong NSPointerArray sau khi thêm các mục đầu tiên là 18, không phải 1.

QED- Nó cho thấy rằng một NSPointerArray thực ra là một mảng, và cho các mục đích của cuộc thảo luận này, NSArray.

Ngoài ra, bbum còn đưa ra các nhận xét bổ sung sau đây:

NSPointerArray chắc chắn nhất hỗ trợ lỗ hổng.

Điều này là giả dối. Một mảng yêu cầu tất cả các mục chứa trong nó chứa một cái gì đó, ngay cả khi cái gì đó là 'không có gì'. Điều này không đúng với một mảng thưa thớt. Đây là định nghĩa của một 'lỗ hổng' cho các mục đích của cuộc thảo luận này. A NSPointerArraykhông chứa holes trong ý nghĩa mảng thưa thớt của thuật ngữ.

Đó là một trong những điểm viết của lớp. Bạn phải đặt số đầu tiên.

Nó là không hợp lý để "thiết lập số lượng" của một mảng thưa thớt.

Cho dù việc thực hiện nội bộ là một mảng thưa thớt hoặc một băm hoặc, vv, là một chi tiết thực hiện.

Điều này đúng. Tuy nhiên, tài liệu cho NSPointerArray không thực hiện bất kỳ tham chiếu nào đến cách nó triển khai hoặc quản lý mảng các mục của nó. Hơn nữa, nó không nói bất cứ nơi nào mà NSPointerArray "quản lý hiệu quả một mảng con trỏ NULL."

QED-bbum tùy thuộc vào hành vi không có giấy tờ Đó là một NSPointerArray xử lý hiệu quả NULL con trỏ thông qua một mảng thưa thớt nội bộ. Đang hành vi không có giấy tờ, hành vi này có thể thay đổi bất kỳ lúc nào hoặc thậm chí không áp dụng cho tất cả các ứng dụng của NSPointerArray. Thay đổi trong hành vi này sẽ là thảm khốc nếu số chỉ mục cao nhất được lưu trữ trong nó đủ lớn (~ 2 ^ 26).

Và, trên thực tế, nó không được thực hiện như một bộ nhớ lớn ...

Một lần nữa, đây là một riêng tư chi tiết triển khai không có giấy tờ. Nó là vô cùng thực hành lập trình kém phụ thuộc vào loại hành vi này.


-4
2017-09-03 23:56



Tôi sẽ đi ra ngoài trên một chi ở đây và đề nghị rằng Bbum mô tả NSPointerArray như là một mảng thưa thớt bởi vì ông có kiến ​​thức trực tiếp về cách nó được thực hiện. - NSResponder
Tôi sẽ đưa ra giả định tiên đề rằng định nghĩa này từ tài liệu khẳng định rằng đây là một phân lớp "hợp lý" của NSArray. Đó sẽ là một giả định không chính xác. - bbum
Chúng ta không thể giải quyết đối số này bằng cách thêm một danh mục đơn giản vào NSPointerArray: @implementation NSPointerArray (HHAdditions) - (void) setPointer: (void *) mục atIndex: (NSUInteger) index {if (! (Index <[self count]) ) {[self setCount: (chỉ mục + 1)]; } [self replacePointerAtIndex: chỉ mục withPointer: item]; } @end Now count được đặt tự động. Các mục được thay thế thay vì được dịch chuyển. - Pierre Bernard