2011-01-28 45 views
10

Tôi cần thực hiện những gì tôi cảm thấy là một chức năng cơ bản nhưng tôi không thể tìm thấy bất kỳ tài liệu nào về cách thực hiện. Hãy giúp tôi!Mục tiêu-C: Đếm số lần một đối tượng xuất hiện trong một mảng?

Tôi cần đếm số lần một đối tượng nhất định xảy ra trong một mảng. Xem ví dụ:

array = NSArray arrayWithObjects:@"Apple", @"Banana", @"Cantaloupe", @"Apple", @"DragonFruit", @"Eggplant", @"Apple", @"Apple", @"Guava",nil]retain]; 

Làm cách nào tôi có thể lặp qua mảng và đếm số lần tìm chuỗi @ "Apple"?

Mọi trợ giúp đều được đánh giá cao!

+1

Nếu đây là thao tác phổ biến, hãy sử dụng 'NSCountedSet'. – bbum

Trả lời

13

Một đơn giản và cụ thể câu trả lời:

int occurrences = 0; 
for(NSString *string in array){ 
    occurrences += ([string isEqualToString:@"Apple"]?1:0); //certain object is @"Apple" 
} 
NSLog(@"number of occurences %d", occurrences); 

PS: Câu trả lời Martin Babacaev là khá tốt quá. Lặp đi lặp lại nhanh hơn với các khối nhưng trong trường hợp cụ thể này với rất ít yếu tố tôi đoán không có lợi ích rõ ràng. Tôi sẽ sử dụng mặc dù :)

+2

tại sao không chỉ 'lần xuất hiện + = [chuỗi isEqualToString: @" Apple "];'? –

+0

Bạn nói đúng ... Tôi chỉ muốn làm cho nó rõ ràng hơn;) – nacho4d

+0

Xin lỗi, nó đã cho tôi mãi mãi để chấp nhận câu trả lời này, nhưng nó trông giống như là tốt nhất! Cảm ơn! – EmphaticArmPump

3
- (int) numberOfOccurrencesForString:(NSString*)needle inArray:(NSArray*)haystack { 
    int count = 0; 

    for(NSString *str in haystack) { 
     if([str isEqualToString:needle]) { 
      count++; 
     } 
    } 

    return count; 
} 
16

Thêm một giải pháp, sử dụng các khối (làm việc chẳng hạn):

NSInteger occurrences = [[array indexesOfObjectsPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {return [obj isEqual:@"Apple"];}] count]; 
NSLog(@"%d",occurrences); 
+0

Hi Martin, câu trả lời này có một dấu ngoặc đóng không liên quan gây ra lỗi thời gian biên dịch. Tôi đã thử chỉnh sửa trong SO, nhưng chúng yêu cầu tối thiểu 6 chỉnh sửa ký tự để gửi bản sửa lỗi. Great dòng mặc dù! – rob5408

+0

Cảm ơn Rob! Cố định .. –

4

tôi sẽ khuyến khích bạn đặt chúng vào một từ điển (Objective phiên bản của một bản đồ C) . Chìa khóa của từ điển là đối tượng và giá trị phải là số đếm. Nó phải là một MutableDictionary tất nhiên. Nếu không tìm thấy mục này, hãy thêm nó và đặt số đếm là 1.

+1

Như đã đề cập bởi @Rob, lặp qua mảng của bạn và xây dựng một 'NSMutableDictionary' với giá trị, chẳng hạn như' A', làm khóa và đếm số mà khóa đã được xem là giá trị. – raidfive

2

Tôi đã bỏ phiếu cho câu trả lời của Rob, nhưng tôi muốn thêm một số mã mà tôi hy vọng sẽ có một số trợ giúp.

NSArray *array = [[NSArray alloc] initWithObjects:@"A", @"B", @"B", @"B", @"C", @"D", @"E", @"M", @"X", @"X", nil]; 

NSMutableDictionary *dictionary = [[NSMutableDictionary alloc]init]; 
for(int i=0; i < [array count]; i++) { 
    NSString *s = [array objectAtIndex:i]; 
    if (![dictionary objectForKey:s]) { 
     [dictionary setObject:[NSNumber numberWithInt:1] forKey:s]; 
    } else { 
     [dictionary setObject:[NSNumber numberWithInt:[dictionary objectForKey:s] intValue]+1 forKey:s]; 
    } 
} 

for(NSString *k in [dictionary keyEnumerator]) { 
    NSNumber *number = [dictionary objectForKey:k]; 
    NSLog(@"Value of %@:%d", k, [number intValue]); 
} 
2

Nếu mảng được sắp xếp như trong báo cáo sự cố thì bạn không cần sử dụng từ điển.

Bạn có thể tìm số nguyên tố độc đáo hiệu quả hơn bằng cách chỉ thực hiện 1 lần quét tuyến tính và tăng bộ đếm khi bạn thấy 2 phần tử liên tiếp giống nhau.

Giải pháp từ điển là O (nlog (n)), trong khi giải pháp tuyến tính là O (n).

Dưới đây là một số mã giả cho các giải pháp tuyến tính:

array = A,B,B,B,B,C,C,D,E,M,X,X #original array 
array = array + -1 # array with a dummy sentinel value to avoid testing corner cases. 

# Start with the first element. You want to add some error checking here if array is empty. 
last = array[0] 
count = 1 # you have seen 1 element 'last' so far in the array. 
for e in array[1..]: # go through all the elements starting from the 2nd one onwards 
    if e != last: # if you see a new element then reset the count 
    print "There are " + count + " " + last elements 
    count = 1 # unique element count 
    else: 
    count += 1 
    last = e 
15

Sử dụng một NSCountedSet; nó sẽ nhanh hơn một từ điển và được thiết kế để giải quyết chính xác vấn đề đó.

NSCountedSet *cs = [NSCountedSet new]; 
for(id anObj in someArray) 
    [cs addObject: anObj]; 

// then, you can access counts like this: 
.... count = [cs countForObject: anObj]; ... 

[cs release]; 
15

Như @bbum đã nói, sử dụng bộ NSCounted. Có một thét initializer sẽ chuyển đổi một mảng trực tiếp vào một bộ đếm:

NSArray *array = [[NSArray alloc] initWithObjects:@"A", @"B", @"X", @"B", @"C", @"D", @"B", @"E", @"M", @"X", nil]; 
    NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:array]; 
    NSLog(@"%@", countedSet); 

NSLog đầu ra: (D [1], M [1], E [1], A [1], B [3 ], X [2], C [1])

Chỉ cần truy cập mục:

count = [countedSet countForObject: anObj]; ... 
+0

Câu trả lời này rất tốt. Nhưng, bạn có thể có được mảng với các thành viên trùng lặp từ NSCountedSet không? (Ví dụ, để lưu trữ nó trong một tập tin plist). –

+0

Bây giờ tôi nghĩ về nó, một phương pháp để chuyển đổi NSCountedSet <-> NSDictionary (các khóa là các đối tượng trong bộ đếm, các giá trị là số đếm) sẽ tốt hơn, bởi vì plist sẽ nhỏ hơn. Tôi đã googling, và không thể tìm thấy bất cứ điều gì. Có lẽ chúng ta cần phải thực hiện một phương pháp như vậy bằng tay. –

0

Nếu bạn muốn nó chung chung hơn, hoặc bạn muốn tính bình đẳng/đối tượng khác nhau trong mảng, hãy thử này:

Ký "!"Đếm KHÁC giá trị. Nếu bạn muốn CÙNG giá trị, loại bỏ '!'

int count = 0; 
    NSString *wordToCheck = [NSString string]; 
    for (NSString *str in myArray) { 
    if(![str isEqualToString:wordToCheck]) { 
     wordToCheck = str; 
     count++; 
    } 
    } 

hy vọng điều này giúp cộng đồng!

Tôi đã sử dụng nó để thêm số chính xác các bộ phận trong UITableView!

2

mã hoàn chỉnh với tham chiếu đến @bbum và @Zaph

NSArray *myArray = [[NSArray alloc] initWithObjects:@"A", @"B", @"X", @"B", @"C", @"D", @"B", @"E", @"M", @"X", nil]; 
NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:myArray]; 

for (NSString *item in countedSet) { 

    int count = [countedSet countForObject: item]; 
    NSLog(@"the String ' %@ ' appears %d times in the array",item,count); 
} 

Cảm ơn bạn.

0

Bạn có thể làm theo cách này,

NSArray *array = [[NSArray alloc] initWithObjects:@"A", @"B", @"X", @"B", @"C", @"D", @"B", @"E", @"M", @"X", nil]; 

NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:array]; 
NSArray *uniqueStates = [[orderedSet set] allObjects]; 

NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:array]; 
for(int i=0;i<[uniqueStates count];i++){ 
NSLog(@"%@ %d",[uniqueStates objectAtIndex:i], [countedSet countForObject: [uniqueStates objectAtIndex:i]]); 
} 

Kết quả là như sau: A 1

7

Chỉ cần đi qua câu hỏi khá cũ này. Tôi khuyên bạn nên sử dụng một số NSCountedSet:

NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:array]; 
NSLog(@"Occurrences of Apple: %u", [countedSet countForObject:@"Apple"]); 
Các vấn đề liên quan