ios - transformar - toque da apple download




Como faço para classificar um NSMutableArray com objetos personalizados nele? (17)

O que eu quero fazer parece bastante simples, mas não consigo encontrar nenhuma resposta na web. Eu tenho um NSMutableArray de objetos e digamos que eles são objetos 'Person'. Eu quero classificar o NSMutableArray por Person.birthDate que é um NSDate .

Eu acho que tem algo a ver com esse método:

NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(???)];

Em Java, eu faria meu objeto implementar o Comparable, ou usar o Collections.sort com um comparador personalizado in-line ... como você faz isso no Objective-C?


Compare o método

Você implementa um método de comparação para seu objeto:

- (NSComparisonResult)compare:(Person *)otherObject {
    return [self.birthDate compare:otherObject.birthDate];
}

NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)];

NSSortDescriptor (melhor)

ou geralmente melhor ainda:

NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                           ascending:YES];
NSArray *sortedArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];

Você pode classificar facilmente por várias chaves adicionando mais de uma ao array. Também é possível usar métodos de comparação personalizados. Dê uma olhada na documentação .

Blocos (brilhantes!)

Há também a possibilidade de classificar com um bloco desde o Mac OS X 10.6 e o ​​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];
}];

atuação

Os métodos -compare: e block-based serão um pouco mais rápidos, em geral, do que usar o NSSortDescriptor pois o último depende do KVC. A principal vantagem do método NSSortDescriptor é que ele fornece uma maneira de definir sua ordem de classificação usando dados, em vez de código, o que torna fácil, por exemplo, configurar coisas para que os usuários possam classificar um NSTableView clicando na linha de cabeçalho.


Ordenar Array Em Swift

Para Swifty Person abaixo está uma técnica muito limpa para alcançar o objetivo acima para globalmente. Vamos ter um exemplo de classe customizada de User que possui alguns atributos.

class User: NSObject {
    var id: String?
    var name: String?
    var email: String?
    var createdDate: Date?
}

Agora temos um array que precisamos classificar com base em createdDate ascendente e / ou decrescente. Então vamos adicionar uma função para comparação de datas.

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
    }
}

Agora vamos ter uma extension de Array for User . Em palavras simples, vamos adicionar alguns métodos apenas para aqueles Array que só possuem objetos User nele.

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
    }
}

Uso para Ordem Ascendente

let sortedArray = someArray.sortUserByDate(.orderedAscending)

Uso para ordem decrescente

let sortedArray = someArray.sortUserByDate(.orderedAscending)

Uso para o mesmo pedido

let sortedArray = someArray.sortUserByDate(.orderedSame)

O método acima na extension só será acessível se o Array for do tipo [User] || Array<User>


Acabei de fazer uma classificação de vários níveis com base em requisitos personalizados.

// classifica os valores

    [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


Blocos do iOS 4 vão te salvar :)

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 um pouco de descrição


Eu fiz isso no iOS 4 usando um bloco. Tive que converter os elementos da minha matriz de id para o meu tipo de classe. Nesse caso, era uma classe chamada Score com uma propriedade chamada points.

Além disso, você precisa decidir o que fazer se os elementos de sua matriz não forem do tipo certo. Para este exemplo, acabei de retornar NSOrderedSame , no entanto, em meu código, apesar de uma exceção.

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;

PS: Isso está classificando em ordem decrescente.


Eu tentei de tudo, mas isso funcionou para mim. Em uma classe eu tenho outra classe chamada " crimeScene ", e quero classificar por uma propriedade de " crimeScene ".

Isso funciona como um encanto:

NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:@"crimeScene.distance" ascending:YES];
[self.arrAnnotations sortUsingDescriptors:[NSArray arrayWithObject:sorter]];

Há um passo em falta na segunda resposta de Georg Schölly , mas funciona bem então.

NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                              ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptor:sortDescriptors];

No meu caso, eu uso "sortedArrayUsingComparator" para classificar uma matriz. Veja o código abaixo.

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];
}];

Também meu objetivo é,

@interface ContactListData : JsonData
@property(nonatomic,strong) NSString * contactName;
@property(nonatomic,strong) NSString * contactSurname;
@property(nonatomic,strong) NSString * contactPhoneNumber;
@property(nonatomic) BOOL isSelected;
@end

Os protocolos e programação funcional do Swift tornam isso muito fácil. Basta fazer com que sua classe esteja em conformidade com o protocolo Comparable, implementar os métodos exigidos pelo protocolo e usar a função ordenada ordenada (por:) para criar um array ordenado sem precisar usar matrizes mutáveis ​​pelo caminho.

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)

Para NSMutableArray , use o método sortUsingSelector . Ele classifica o lugar, sem criar uma nova instância.


Seus objetos Person precisam implementar um método, digamos compare: que leva outro objeto Person e retorna NSComparisonResult acordo com o relacionamento entre os dois objetos.

Em seguida, você chamaria sortedArrayUsingSelector: com @selector(compare:) e isso deve ser feito.

Existem outras maneiras, mas, até onde sei, não há cacau-equiv da interface Comparable . Usando sortedArrayUsingSelector: é provavelmente a maneira mais indolor de fazer isso.


Veja o método NSMutableArray sortUsingFunction:context:

Você precisará configurar uma função de comparação que obtenha dois objetos (do tipo Person , já que você está comparando dois objetos Person ) e um parâmetro de contexto .

Os dois objetos são apenas instâncias de Person . O terceiro objeto é uma string, por exemplo, @ "birthDate".

Esta função retorna um NSComparisonResult : Retorna NSOrderedAscending se PersonA.birthDate < PersonB.birthDate . Ele retornará NSOrderedDescending se PersonA.birthDate > PersonB.birthDate . Finalmente, retornará NSOrderedSame se PersonA.birthDate == PersonB.birthDate .

Este é um pseudocódigo áspero; você precisará detalhar o que significa para uma data ser "menos", "mais" ou "igual" a outra data (como comparar segundos-desde-epoch etc.):

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;
}

Se você quer algo mais compacto, você pode usar operadores ternários:

NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) {
  return ([firstPerson birthDate] < [secondPerson birthDate]) ? NSOrderedAscending : ([firstPerson birthDate] > [secondPerson birthDate]) ? NSOrderedDescending : NSOrderedSame;
}

Inlining poderia talvez acelerar um pouco, se você fizer isso muito.


Você tem que criar sortDescriptor e então você pode classificar o nsmutablearray usando sortDescriptor como abaixo.

 let sortDescriptor = NSSortDescriptor(key: "birthDate", ascending: true, selector: #selector(NSString.compare(_:)))
 let array = NSMutableArray(array: self.aryExist.sortedArray(using: [sortDescriptor]))
 print(array)

Você usa NSSortDescriptor para classificar um NSMutableArray com objetos personalizados

 NSSortDescriptor *sortingDescriptor;
 sortingDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                       ascending:YES];
 NSArray *sortArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];

-(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];

Obrigado, está funcionando bem ...





nsmutablearray