ios - sortedarrayusingcomparator - xcode array sort
NSMutableArray를 사용자 정의 객체로 정렬하려면 어떻게합니까? (17)
내가하고 싶은 일은 아주 단순 해 보이지만 웹에서 답을 찾을 수는 없습니다. 객체의 NSMutableArray
를 가지고 있고 그것들이 'Person'객체라고 가정 해 봅시다. NSDate
Person.birthDate에 의해 NSMutableArray
를 정렬하려고합니다.
나는 그것이이 방법과 관련이 있다고 생각한다.
NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(???)];
Java에서 내 개체를 Comparable로 구현하거나 인라인 사용자 지정 비교기로 Collections.sort를 사용합니다. Objective-C에서이 작업을 수행하는 방법은 무엇입니까?
Swift에서 배열 정렬
Swifty
Person은 아래의 목표를 달성하기위한 매우 깨끗한 기술입니다. 몇 가지 속성을 가진 User
의 예제 사용자 정의 클래스가 있습니다.
class User: NSObject {
var id: String?
var name: String?
var email: String?
var createdDate: Date?
}
이제 createdDate
를 기준으로 오름차순 또는 내림차순으로 정렬해야하는 배열이 있습니다. 그래서 날짜 비교를위한 함수를 추가 할 수 있습니다.
class User: NSObject {
var id: String?
var name: String?
var email: String?
var createdDate: Date?
func checkForOrder(_ otherUser: User, _ order: ComparisonResult) -> Bool {
if let myCreatedDate = self.createdDate, let othersCreatedDate = otherUser.createdDate {
//This line will compare both date with the order that has been passed.
return myCreatedDate.compare(othersCreatedDate) == order
}
return false
}
}
이제 User
위한 Array
extension
을 허용하십시오. 간단히 말해, User
객체 만있는 Array에 대해서만 몇 가지 메소드를 추가 할 수 있습니다.
extension Array where Element: User {
//This method only takes an order type. i.e ComparisonResult.orderedAscending
func sortUserByDate(_ order: ComparisonResult) -> [User] {
let sortedArray = self.sorted { (user1, user2) -> Bool in
return user1.checkForOrder(user2, order)
}
return sortedArray
}
}
오름차순의 사용법
let sortedArray = someArray.sortUserByDate(.orderedAscending)
내림차순 사용
let sortedArray = someArray.sortUserByDate(.orderedAscending)
동일한 주문에 대한 사용
let sortedArray = someArray.sortUserByDate(.orderedSame)
Array
의[User]
|| 유형 인 경우에만extension
위의 메소드에 액세스 할 수 있습니다.Array<User>
메소드 비교
당신은 당신의 객체를위한 compare-method를 구현한다 :
- (NSComparisonResult)compare:(Person *)otherObject {
return [self.birthDate compare:otherObject.birthDate];
}
NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)];
NSSortDescriptor (더 나은)
또는 보통 더 나은 :
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
ascending:YES];
NSArray *sortedArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];
배열에 하나 이상을 추가하여 여러 키로 쉽게 정렬 할 수 있습니다. 커스텀 콤퍼레이터 메소드를 사용하는 것도 가능합니다. 문서를보십시오 .
블록 (빛나는!)
Mac OS X 10.6 및 iOS 4 이후 블록을 사용하여 정렬 할 수도 있습니다.
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSDate *first = [(Person*)a birthDate];
NSDate *second = [(Person*)b birthDate];
return [first compare:second];
}];
공연
후자는 KVC를 사용 NSSortDescriptor
때문에 NSSortDescriptor
를 사용하는 것보다 -compare:
및 블록 기반 메서드는 일반적으로 훨씬 빠릅니다. NSSortDescriptor
메서드의 가장 큰 장점은 코드가 아닌 데이터를 사용하여 정렬 순서를 정의 할 수있는 방법을 제공한다는 것입니다. 예를 들어 머리글 행을 클릭하여 NSTableView
를 정렬 할 수 있도록 설정할 수 있습니다.
Swift의 프로토콜과 함수형 프로그래밍을 사용하면 클래스가 Comparable 프로토콜을 준수하도록하고 프로토콜에 필요한 메소드를 구현 한 다음 정렬 된 (by :) 고차 함수를 사용하여 정렬 된 배열을 사용할 필요없이 쉽게 만들 수 있습니다 그런데 배열을 변경할 수 있습니다.
class Person: Comparable {
var birthDate: NSDate?
let name: String
init(name: String) {
self.name = name
}
static func ==(lhs: Person, rhs: Person) -> Bool {
return lhs.birthDate === rhs.birthDate || lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedSame
}
static func <(lhs: Person, rhs: Person) -> Bool {
return lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedAscending
}
static func >(lhs: Person, rhs: Person) -> Bool {
return lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedDescending
}
}
let p1 = Person(name: "Sasha")
p1.birthDate = NSDate()
let p2 = Person(name: "James")
p2.birthDate = NSDate()//he is older by miliseconds
if p1 == p2 {
print("they are the same") //they are not
}
let persons = [p1, p2]
//sort the array based on who is older
let sortedPersons = persons.sorted(by: {$0 > $1})
//print sasha which is p1
print(persons.first?.name)
//print James which is the "older"
print(sortedPersons.first?.name)
iOS 4 블록을 저장하면됩니다 :)
featuresArray = [[unsortedFeaturesArray sortedArrayUsingComparator: ^(id a, id b)
{
DMSeatFeature *first = ( DMSeatFeature* ) a;
DMSeatFeature *second = ( DMSeatFeature* ) b;
if ( first.quality == second.quality )
return NSOrderedSame;
else
{
if ( eSeatQualityGreen == m_seatQuality || eSeatQualityYellowGreen == m_seatQuality || eSeatQualityDefault == m_seatQuality )
{
if ( first.quality < second.quality )
return NSOrderedAscending;
else
return NSOrderedDescending;
}
else // eSeatQualityRed || eSeatQualityYellow
{
if ( first.quality > second.quality )
return NSOrderedAscending;
else
return NSOrderedDescending;
}
}
}] retain];
http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html 설명이 약간 있습니다.
sortDescriptor를 생성 한 다음 아래처럼 sortDescriptor를 사용하여 nsmutablearray를 정렬 할 수 있습니다.
let sortDescriptor = NSSortDescriptor(key: "birthDate", ascending: true, selector: #selector(NSString.compare(_:)))
let array = NSMutableArray(array: self.aryExist.sortedArray(using: [sortDescriptor]))
print(array)
나는 모든 것을 시도했다. 그러나 이것은 나를 위해 일했다. 어떤 클래스에서는 " crimeScene
"이라는 또 다른 클래스가 crimeScene
, " crimeScene
"속성으로 정렬하려고합니다.
이것은 매력처럼 작동합니다.
NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:@"crimeScene.distance" ascending:YES];
[self.arrAnnotations sortUsingDescriptors:[NSArray arrayWithObject:sorter]];
방금 사용자 지정 요구 사항을 기반으로 여러 수준의 정렬을 수행했습니다.
// 값을 정렬합니다.
[arrItem sortUsingComparator:^NSComparisonResult (id a, id b){
ItemDetail * itemA = (ItemDetail*)a;
ItemDetail* itemB =(ItemDetail*)b;
//item price are same
if (itemA.m_price.m_selling== itemB.m_price.m_selling) {
NSComparisonResult result= [itemA.m_itemName compare:itemB.m_itemName];
//if item names are same, then monogramminginfo has to come before the non monograme item
if (result==NSOrderedSame) {
if (itemA.m_monogrammingInfo) {
return NSOrderedAscending;
}else{
return NSOrderedDescending;
}
}
return result;
}
//asscending order
return itemA.m_price.m_selling > itemB.m_price.m_selling;
}];
https://sites.google.com/site/greateindiaclub/mobil-apps/ios/multilevelsortinginiosobjectivec
블록을 사용하여 iOS 4에서이 작업을 수행했습니다. ID에서 내 클래스 유형으로 배열의 요소를 캐스팅해야했습니다. 이 경우 점수라는 속성이있는 점수라는 클래스였습니다.
또한 배열의 요소가 올바른 형식이 아닌 경우 수행 할 작업을 결정해야합니다.이 예제에서는 NSOrderedSame
반환했지만 예외는 있지만 코드에서는 예외가 있습니다.
NSArray *sorted = [_scores sortedArrayUsingComparator:^(id obj1, id obj2){
if ([obj1 isKindOfClass:[Score class]] && [obj2 isKindOfClass:[Score class]]) {
Score *s1 = obj1;
Score *s2 = obj2;
if (s1.points > s2.points) {
return (NSComparisonResult)NSOrderedAscending;
} else if (s1.points < s2.points) {
return (NSComparisonResult)NSOrderedDescending;
}
}
// TODO: default is the same?
return (NSComparisonResult)NSOrderedSame;
}];
return sorted;
추신 : 이것은 내림차순으로 정렬됩니다.
필자의 경우 "sortedArrayUsingComparator"를 사용하여 배열을 정렬합니다. 아래 코드를보십시오.
contactArray = [[NSArray arrayWithArray:[contactSet allObjects]] sortedArrayUsingComparator:^NSComparisonResult(ContactListData *obj1, ContactListData *obj2) {
NSString *obj1Str = [NSString stringWithFormat:@"%@ %@",obj1.contactName,obj1.contactSurname];
NSString *obj2Str = [NSString stringWithFormat:@"%@ %@",obj2.contactName,obj2.contactSurname];
return [obj1Str compare:obj2Str];
}];
또한 나의 목표는,
@interface ContactListData : JsonData
@property(nonatomic,strong) NSString * contactName;
@property(nonatomic,strong) NSString * contactSurname;
@property(nonatomic,strong) NSString * contactPhoneNumber;
@property(nonatomic) BOOL isSelected;
@end
Georg Schölly의 두 번째 대답 에서 빠진 단계가 있지만 잘 작동합니다.
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate"
ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptor:sortDescriptors];
NSMutableArray
메서드 sortUsingFunction:context:
참조하십시오 sortUsingFunction:context:
두 개의 객체 (두 개의 Person
객체를 비교하기 때문에 Person
유형의 객체)와 컨텍스트 매개 변수를 취하는 비교 함수를 설정해야합니다.
두 객체는 Person
인스턴스입니다. 세 번째 객체는 @ "birthDate"와 같은 문자열입니다.
이 함수는 NSComparisonResult
반환합니다. PersonA.birthDate
< PersonB.birthDate
경우 NSOrderedAscending
반환합니다. PersonA.birthDate
> PersonB.birthDate
경우 NSOrderedDescending
을 반환합니다. 마지막으로 PersonA.birthDate
== PersonB.birthDate
경우 NSOrderedSame
을 반환합니다.
거친 가상 코드입니다. 당신은 한 날짜가 다른 날짜에 "덜", "더"또는 "동등"하다는 의미가 무엇인지 육체화해야합니다 (예 : 초를 비교 한 것 등).
NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) {
if ([firstPerson birthDate] < [secondPerson birthDate])
return NSOrderedAscending;
else if ([firstPerson birthDate] > [secondPerson birthDate])
return NSOrderedDescending;
else
return NSOrderedSame;
}
보다 작은 것을 원한다면 삼항 연산자를 사용할 수 있습니다 :
NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) {
return ([firstPerson birthDate] < [secondPerson birthDate]) ? NSOrderedAscending : ([firstPerson birthDate] > [secondPerson birthDate]) ? NSOrderedDescending : NSOrderedSame;
}
당신이 이것을 많이한다면, 인라이닝은 아마도 약간의 속도를 낼 수 있습니다.
NSMutableArray
의 경우에는 sortUsingSelector
메소드를 사용하십시오. 새 인스턴스를 만들지 않고도 it-place를 정렬합니다.
NSNumbers
의 배열을 정렬하는 경우에는 1 회의 호출로 정렬 할 수 있습니다.
[arrayToSort sortUsingSelector: @selector(compare:)];
배열 ( NSNumber
개체)의 개체가 compare 메서드를 구현하기 때문에 작동합니다. NSString
객체 나 심지어 compare 메소드를 구현하는 커스텀 데이터 객체의 배열에 대해서도 똑같이 할 수있다.
다음은 비교기 블록을 사용하는 몇 가지 예제 코드입니다. 각 사전이 "sort_key"키에 숫자를 포함하는 사전 배열을 정렬합니다.
#define SORT_KEY @\"sort_key\"
[anArray sortUsingComparator:
^(id obj1, id obj2)
{
NSInteger value1 = [[obj1 objectForKey: SORT_KEY] intValue];
NSInteger value2 = [[obj2 objectForKey: SORT_KEY] intValue];
if (value1 > value2)
{
return (NSComparisonResult)NSOrderedDescending;
}
if (value1 < value2)
{
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
위의 코드는 각 정렬 키에 대한 정수 값을 가져 와서 비교하는 작업을 수행하는 방법을 보여줍니다. NSNumber
객체는 compare 메소드를 구현하기 때문에 훨씬 간단하게 다시 작성할 수 있습니다.
#define SORT_KEY @\"sort_key\"
[anArray sortUsingComparator:
^(id obj1, id obj2)
{
NSNumber* key1 = [obj1 objectForKey: SORT_KEY];
NSNumber* key2 = [obj2 objectForKey: SORT_KEY];
return [key1 compare: key2];
}];
또는 비교기의 몸체를 1 줄까지 증류 할 수 있습니다.
return [[obj1 objectForKey: SORT_KEY] compare: [obj2 objectForKey: SORT_KEY]];
나는 코드가 읽기 쉽고 디버깅하기 쉽기 때문에 간단한 문장과 많은 임시 변수를 선호하는 경향이있다. 컴파일러는 어쨌든 임시 변수를 최적화하여 올인원 버전에 아무런 이점도 없습니다.
Person
객체는 다른 Person
객체를 취하는 compare:
메소드를 구현해야하며 두 객체 간의 관계에 따라 NSComparisonResult
반환 NSComparisonResult
합니다.
그런 다음 sortedArrayUsingSelector:
를 @selector(compare:)
와 호출하면 완료됩니다.
다른 방법이 있지만, 필자가 아는 한 Comparable
인터페이스의 코코아 -equiv는 없다. sortedArrayUsingSelector:
사용하기 sortedArrayUsingSelector:
아마도 가장 고통 sortedArrayUsingSelector:
방법 일 것입니다.
-(NSMutableArray*) sortArray:(NSMutableArray *)toBeSorted
{
NSArray *sortedArray;
sortedArray = [toBeSorted sortedArrayUsingComparator:^NSComparisonResult(id a, id b)
{
return [a compare:b];
}];
return [sortedArray mutableCopy];
}
NSMutableArray *stockHoldingCompanies = [NSMutableArray arrayWithObjects:fortune1stock,fortune2stock,fortune3stock,fortune4stock,fortune5stock,fortune6stock , nil];
NSSortDescriptor *sortOrder = [NSSortDescriptor sortDescriptorWithKey:@"companyName" ascending:NO];
[stockHoldingCompanies sortUsingDescriptors:[NSArray arrayWithObject:sortOrder]];
NSEnumerator *enumerator = [stockHoldingCompanies objectEnumerator];
ForeignStockHolding *stockHoldingCompany;
NSLog(@"Fortune 6 companies sorted by Company Name");
while (stockHoldingCompany = [enumerator nextObject]) {
NSLog(@"===============================");
NSLog(@"CompanyName:%@",stockHoldingCompany.companyName);
NSLog(@"Purchase Share Price:%.2f",stockHoldingCompany.purchaseSharePrice);
NSLog(@"Current Share Price: %.2f",stockHoldingCompany.currentSharePrice);
NSLog(@"Number of Shares: %i",stockHoldingCompany.numberOfShares);
NSLog(@"Cost in Dollars: %.2f",[stockHoldingCompany costInDollars]);
NSLog(@"Value in Dollars : %.2f",[stockHoldingCompany valueInDollars]);
}
NSLog(@"===============================");
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];
고마워, 잘하고있어.