Sắp xếp NSArray của chuỗi ngày hoặc đối tượng


86

Tôi có một NSArraychứa chuỗi ngày (tức là NSString) như thế này: "Thu, 21 tháng 5 09 19:10:09 -0700"

Tôi cần sắp xếp NSArraytheo ngày tháng. Tôi đã nghĩ về việc chuyển đổi chuỗi ngày tháng thành một NSDateđối tượng trước tiên, nhưng lại bị mắc kẹt ở đó về cách sắp xếp theo NSDateđối tượng.

Cảm ơn.


Được gắn thẻ lại vì điều này liên quan đến khuôn khổ Foundation và không dành riêng cho iPhone.
Quinn Taylor,

Câu trả lời:


110

Lưu trữ ngày tháng dưới dạng NSDateđối tượng trong Mảng NS (Có thể thay đổi), sau đó sử dụng -[NSArray sortedArrayUsingSelector:hoặc -[NSMutableArray sortUsingSelector:]và chuyển @selector(compare:)làm tham số. Các -[NSDate compare:]phương pháp sẽ đặt hàng ngày trong thứ tự tăng dần cho bạn. Điều này đơn giản hơn việc tạo một NSSortDescriptorvà đơn giản hơn nhiều so với việc viết hàm so sánh của riêng bạn. ( NSDatecác đối tượng biết cách tự so sánh chúng với nhau ít nhất một cách hiệu quả như chúng ta có thể hy vọng đạt được với mã tùy chỉnh.)


11
Không rõ câu hỏi ban đầu hỏi về việc sắp xếp một mảng ngày tháng hay sắp xếp một mảng đối tượng có trường ngày tháng. Đây là cách tiếp cận dễ dàng nhất nếu là cách trước, nhưng nếu là cách sau, NSSortDescriptor là cách để đi.
smorgan

@smorgan NSSortDescriptor xử lý ngày tháng như thế nào?
Ash

Cảm ơn sự giúp đỡ của bạn, tôi nghĩ chúng ta nên đọc thêm trong Apple Docs nhưng nó có vẻ quá nhàm chán, cho đến khi bạn sử dụng nó.
Abo3atef

1
Bạn có thể hiển thị điều này trong một đoạn mã làm ví dụ không? Cảm ơn trước.
uplearnedu.com

115

Nếu tôi có một NSMutableArraytrong các đối tượng có loại trường "beginDate", NSDatetôi đang sử dụng một trường NSSortDescriptornhư dưới đây:

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];

3
Tôi biết rất nhiều thời gian đã trôi qua (khi câu trả lời trước đó được chấp nhận, có thể chưa có NSSortDescriptor), nhưng để sử dụng trong tương lai, câu trả lời này phải là câu trả lời thích hợp.
Vive

1
Đây là một giải pháp tuyệt vời. giải quyết vấn đề của tôi trong một vài dòng code.Thanx một tấn @vinzenzweber
Pratyusha Terli

1
Thực sự ... tôi thực sự bị sốc vì nó hoạt động ngay từ lần chạy đầu tiên! Tôi nghĩ rằng initWithKey được dành riêng cho từ điển nơi khóa được định nghĩa, nhưng tất cả những gì bạn cần làm là tham chiếu một thuộc tính trong một mảng đối tượng? Hãy để ánh sáng tỏa sáng vinzenzweberskavitchski !!
whyoz

NSSortDescriptor đã xuất hiện từ OS X 10.3 vào cuối năm 2003. Đây là một kịch bản hơi khác, trong đó ngày tháng là một trường trong một đối tượng khác. Với API hiện đại hơn nữa, bạn cũng có thể sử dụng -[NSMutableArray sortUsingComparator:](10.6+) và chuyển một khối trả về kết quả của việc gọi -compare:hai trường. Nó có lẽ sẽ nhanh hơn việc gọi -valueForKey:từng đối tượng. Bạn thậm chí có thể sử dụng -sortWithOptions:usingComparator:và chuyển các tùy chọn để sắp xếp đồng thời.
Quinn Taylor

NSSortDescriptor ở trên xử lý ngày nil như thế nào? Chúng ta có cần phải cho người mô tả biết phải làm gì với chúng nếu có, làm thế nào?
Ash

17

Bạn cũng có thể sử dụng một cái gì đó như sau:

//Sort the array of items by  date
    [self.items sortUsingComparator:^NSComparisonResult(id obj1, id obj2){
        return [obj2.date compare:obj1.date];
    }];

Nhưng điều này giả định rằng ngày được lưu trữ dưới dạng NSDatekháNString , không có vấn đề gì để thực hiện / làm. Tốt hơn là tôi cũng khuyên bạn nên lưu trữ dữ liệu ở định dạng thô. Giúp bạn thao tác dễ dàng hơn trong những trường hợp như thế này.


9

Bạn có thể sử dụng các khối để sắp xếp tại chỗ:

sortedDatesArray = [[unsortedDatesArray sortedArrayUsingComparator: ^(id a, id b) {
    NSDate *d1 = [NSDate dateWithString: s1];
    NSDate *d2 = [NSDate dateWithString: s2];
    return [d1 compare: d2];
}];

Tôi khuyên bạn nên chuyển đổi tất cả các chuỗi của mình thành ngày tháng trước khi sắp xếp để không thực hiện chuyển đổi nhiều lần hơn các mục ngày tháng. Bất kỳ thuật toán sắp xếp nào cũng sẽ cung cấp cho bạn nhiều chuyển đổi chuỗi từ trước đến nay hơn là số lượng mục trong mảng (đôi khi về cơ bản là nhiều hơn)

thêm một chút về sắp xếp khối: http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html


Đây là một biến thể của cùng một ý tưởng tối ưu phụ do @notoop trình bày. Trong mọi trường hợp, chuyển đổi sang NSDate trước tiên chắc chắn là cách nên làm.
Quinn Taylor,

Ông về cơ bản chỉ cần đặt câu trả lời của tôi với @ câu trả lời notoop của ..... khá cần thiết để bài gấp đôi những người nếu bạn hỏi tôi ....
TheCodingArt

Điều này chậm hơn nhiều so với phân tích cú pháp chuỗi ngày thành mảng NSDate và sau đó sắp xếp mảng NSDate, vì sẽ có thêm 2 * (n - 1) lần phân tích chuỗi. Phân tích cú pháp chuỗi nói chung là công việc nặng nhọc trên CPU.
CarlLee

5

Những gì nó hoạt động trong trường hợp của tôi là như sau:

    NSArray * aUnsorted = [dataToDb allKeys];
    NSArray * arrKeys = [aUnsorted sortedArrayUsingComparator: ^ NSComparisonResult (id obj1, id obj2) {
        NSDateFormatter * df = [[NSDateFormatter CẤP] init];
        [df setDateFormat: @ "dd-MM-yyyy"];
        NSDate * d1 = [df dateFromString: (NSString *) obj1];
        NSDate * d2 = [df dateFromString: (NSString *) obj2];
        return [d1 so sánh: d2];
    }];

Tôi đã có một từ điển, nơi chứa tất cả các khóa ghi ngày tháng ở định dạng dd-MM-yyyy. Và allKeys trả về các khóa từ điển chưa được sắp xếp và tôi muốn trình bày dữ liệu theo thứ tự thời gian.


5

Bạn có thể sử dụng sortedArrayUsingFunction:context:. Đây là một mẫu:

NSComparisonResult dateSort(NSString *s1, NSString *s2, void *context) {
    NSDate *d1 = [NSDate dateWithString:s1];
    NSDate *d2 = [NSDate dateWithString:s2];
    return [d1 compare:d2];
}

NSArray *sorted = [unsorted sortedArrayUsingFunction:dateSort context:nil];

Khi sử dụng a NSMutableArray, bạn có thể sử dụng sortArrayUsingFunction:context:thay thế.


9
Đây là một ý tưởng tồi - một hàm so sánh phải nhanh và không cần phải tạo các đối tượng NSDate từ các chuỗi cho mỗi lần so sánh. Nếu bạn đã sử dụng - [NSDate so sánh:], chỉ cần lưu trữ ngày tháng trong mảng và sử dụng -sortedArrayUsingSelector: trực tiếp.
Quinn Taylor

Tôi nghĩ đây là một giải pháp tốt nếu bạn đang sắp xếp các đối tượng đã có trường NSDate. Không?
GnarlyDog

1
Nếu mảng đã chứa NSDatecác đối tượng, bạn có thể sử dụng câu trả lời của tôi ở trên, hoặc thậm chí sử dụng câu trả lời -[NSMutableArray sortUsingComparator:]đã được thêm vào trong 10.6.
Quinn Taylor

Nếu bạn đang sử dụng một mảng từ điển trong đó có một đối tượng khóa-giá trị cho ngày là NSString cùng với một số đối tượng khóa-giá trị khác, thì giải pháp này là tốt nhất cho đến nay. Chỉ cần sửa đổi một chút bên trong hàm dateSort. Thích! :)
Erfan

4

Khi bạn có một NSDate, bạn có thể tạo một NSSortDescriptorvới initWithKey:ascending:và sau đó sử dụng sortedArrayUsingDescriptors:để thực hiện việc sắp xếp.


Cách tiếp cận này sẽ hiệu quả, nhưng sử dụng -sortedArrayUsingSelector: đơn giản hơn một chút và không yêu cầu tạo thêm một đối tượng.
Quinn Taylor,

Trước khi chỉnh sửa, câu hỏi đã đề cập đến "khóa" ngày tháng ", vì vậy tôi cho rằng đây thực sự là một mảng đối tượng / từ điển có ngày tháng là một trường, không phải là một mảng ngày tháng thô. Trong trường hợp đó, sortedArrayUsingSelector: phức tạp hơn, vì nó yêu cầu viết một quy trình sắp xếp tùy chỉnh để thực hiện việc tra cứu.
smorgan

Vâng, xin lỗi vì bất kỳ sự nhầm lẫn nào - tôi đã xóa tham chiếu đó vì anh ấy chỉ nói rằng anh ấy đang lưu trữ mảng của mình bằng khóa 'ngày tháng' và tôi nhận ra điều đó chỉ khiến câu hỏi trở nên khó hiểu hơn. Bạn chắc chắn đúng về độ phức tạp tương đối với cấu trúc dữ liệu phức tạp hơn.
Quinn Taylor,

2

Swift 3.0

myMutableArray = myMutableArray.sorted(by: { $0.date.compare($1.date) == ComparisonResult.orderedAscending })

1

Thay đổi điều này

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];

Đến

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Date" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];

Chỉ cần thay đổi KEY: nó phải Dateluôn luôn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.