ios - arreglos - how to make an array in xcode




¿Cómo ordeno un NSMutableArray con objetos personalizados en él? (17)

Lo que quiero hacer parece bastante simple, pero no puedo encontrar ninguna respuesta en la web. Tengo un NSMutableArray de objetos, y digamos que son objetos 'Person'. Quiero ordenar el NSMutableArray por Person.birthDate que es un NSDate .

Creo que tiene algo que ver con este método:

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

En Java, haría que mi objeto se implementara como Comparable, o usaría Collections.sort con un comparador personalizado en línea ... ¿cómo se hace esto en Objective-C?


Método de comparación

O implementas un método de comparación para tu objeto:

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

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

NSSortDescriptor (mejor)

o por lo general incluso mejor:

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

Puede ordenar fácilmente por varias claves agregando más de una a la matriz. También es posible usar métodos de comparación personalizados. Echa un vistazo a la documentación .

Bloques (brillante!)

También existe la posibilidad de clasificar con un bloque desde Mac OS X 10.6 y 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];
}];

Actuación

En general, los métodos basados ​​en bloques y de NSSortDescriptor serán bastante más rápidos que usar NSSortDescriptor ya que este último se basa en KVC. La principal ventaja del método NSSortDescriptor es que proporciona una manera de definir su orden de clasificación utilizando datos, en lugar de código, lo que facilita, por ejemplo, configurar las cosas para que los usuarios puedan ordenar un NSTableView haciendo clic en la fila del encabezado.


Ordenar Array En Swift

Para Swifty Person a continuación es una técnica muy limpia para lograr el objetivo por encima de todo el mundo. Permite tener una clase personalizada de ejemplo de User que tiene algunos atributos.

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

Ahora tenemos una matriz que debemos clasificar en base a createdDate ascendente y / o descendente. Así que vamos a agregar una función para la comparación de fechas.

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

Ahora vamos a tener una extension de Array para User . En palabras simples, agreguemos algunos métodos solo para aquellos Array que solo tienen objetos de User .

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 el orden ascendente

let sortedArray = someArray.sortUserByDate(.orderedAscending)

Uso para orden descendente

let sortedArray = someArray.sortUserByDate(.orderedAscending)

Uso para la misma orden

let sortedArray = someArray.sortUserByDate(.orderedSame)

El método anterior en extension solo será accesible si la Array es de tipo [User] || Array<User>


Acabo de hacer una clasificación de niveles múltiples basada en requisitos personalizados.

// ordenar los 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


En mi caso, uso "sortedArrayUsingComparator" para ordenar una matriz. Mira el siguiente código.

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

También mi objeto es,

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

He creado una pequeña biblioteca de métodos de categoría, llamada Linq to ObjectiveC , que facilita este tipo de cosas. Usando el método de sort con un selector de teclas, puede ordenar por birthDate siguiente manera:

NSArray* sortedByBirthDate = [input sort:^id(id person) {
    return [person birthDate];
}]

He usado sortUsingFunction :: en algunos de mis proyectos:

int SortPlays(id a, id b, void* context)
{
    Play* p1 = a;
    Play* p2 = b;
    if (p1.score<p2.score) 
        return NSOrderedDescending;
    else if (p1.score>p2.score) 
        return NSOrderedAscending;
    return NSOrderedSame;
}

...
[validPlays sortUsingFunction:SortPlays context:nil];

Intenté todo, pero esto funcionó para mí. En una clase tengo otra clase llamada " crimeScene ", y quiero ordenar por una propiedad de " crimeScene ".

Esto funciona como un amuleto:

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

Los protocolos y la programación funcional de Swift hacen que sea muy fácil, solo tiene que hacer que su clase se ajuste al protocolo Comparable, implementar los métodos requeridos por el protocolo y luego usar la función ordenada de orden superior (por:) para crear una matriz ordenada sin necesidad de usar matrices mutables por cierto.

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 el método sortUsingSelector . Lo ordena, sin crear una nueva instancia.


Puede utilizar el siguiente método genérico para su propósito. Debería resolver su problema.

//Called method
-(NSMutableArray*)sortArrayList:(NSMutableArray*)arrDeviceList filterKeyName:(NSString*)sortKeyName ascending:(BOOL)isAscending{
    NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:sortKeyName ascending:isAscending];
    [arrDeviceList sortUsingDescriptors:[NSArray arrayWithObject:sorter]];
    return arrDeviceList;
}

//Calling method
[self sortArrayList:arrSomeList filterKeyName:@"anything like date,name etc" ascending:YES];

Sus objetos Person deben implementar un método, digamos compare: que toma otro objeto Person , y devuelve NSComparisonResult según la relación entre los 2 objetos.

Luego llamaría a sortedArrayUsingSelector: con @selector(compare:) y debería hacerse.

Hay otras formas, pero por lo que sé, no hay Cocoa-equ de la interfaz Comparable . Usar sortedArrayUsingSelector: es probablemente la forma más indolora de hacerlo.


Tienes que crear sortDescriptor y luego puedes ordenar la nsmutablearray usando sortDescriptor como abajo.

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

Vea el método de orden de uso de sortUsingFunction:context:

Necesitará configurar una función de comparación que tome dos objetos (de tipo Person , ya que está comparando dos objetos de Person ) y un parámetro de contexto .

Los dos objetos son solo instancias de Person . El tercer objeto es una cadena, por ejemplo, @ "birthDate".

Esta función devuelve un NSComparisonResult : Devuelve NSOrderedAscending si PersonA.birthDate < PersonB.birthDate . NSOrderedDescending if PersonA.birthDate > PersonB.birthDate . Finalmente, devolverá NSOrderedSame si PersonA.birthDate == PersonB.birthDate .

Esto es un pseudocódigo en bruto; Tendrá que desarrollar lo que significa que una fecha sea "menos", "más" o "igual" a otra fecha (como comparar segundos desde la época, 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;
}

Si quieres algo más compacto, puedes usar operadores ternarios:

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

Inlining quizás podría acelerar esto un poco, si haces esto mucho.


iOS 4 bloques te salvarán :)

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 un poco de descripción


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

Gracias, está funcionando bien ...





nsmutablearray