ios - how - ¿Cómo ordeno un NSMutableArray con objetos personalizados en él?
arreglos en xcode (25)
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.
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?
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 laArray
es de tipo[User]
||Array<User>
A partir de iOS 4 también puedes usar bloques para ordenar.
Para este ejemplo en particular, asumo que los objetos en su matriz tienen un método de ''posición'', que devuelve un NSInteger
.
NSArray *arrayToSort = where ever you get the array from... ;
NSComparisonResult (^sortBlock)(id, id) = ^(id obj1, id obj2)
{
if ([obj1 position] > [obj2 position])
{
return (NSComparisonResult)NSOrderedDescending;
}
if ([obj1 position] < [obj2 position])
{
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
};
NSArray *sorted = [arrayToSort sortedArrayUsingComparator:sortBlock];
Nota: la matriz "ordenada" se lanzará automáticamente.
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
Falta un paso en la segunda respuesta de Georg Schölly , pero funciona bien entonces.
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate"
ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptor:sortDescriptors];
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];
Hice esto en iOS 4 usando un bloque. Tuve que lanzar los elementos de mi matriz desde id a mi tipo de clase. En este caso, se trataba de una clase llamada Puntuación con una propiedad llamada puntos.
También debe decidir qué hacer si los elementos de su matriz no son del tipo correcto. Para este ejemplo, acabo de devolver NSOrderedSame
, sin embargo, en mi código, creo que es una excepción.
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;
PD: Esta es la clasificación en orden descendente.
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)
Ordenar NSMutableArray
es muy simple:
NSMutableArray *arrayToFilter =
[[NSMutableArray arrayWithObjects:@"Photoshop",
@"Flex",
@"AIR",
@"Flash",
@"Acrobat", nil] autorelease];
NSMutableArray *productsToRemove = [[NSMutableArray array] autorelease];
for (NSString *products in arrayToFilter) {
if (fliterText &&
[products rangeOfString:fliterText
options:NSLiteralSearch|NSCaseInsensitiveSearch].length == 0)
[productsToRemove addObject:products];
}
[arrayToFilter removeObjectsInArray:productsToRemove];
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];
Si solo está ordenando una serie de NSNumbers
, puede ordenarlos con 1 llamada:
[arrayToSort sortUsingSelector: @selector(compare:)];
Eso funciona porque los objetos en la matriz (objetos NSNumber
) implementan el método de comparación. Podría hacer lo mismo para los objetos NSString
, o incluso para una matriz de objetos de datos personalizados que implementan un método de comparación.
Aquí hay un código de ejemplo usando bloques de comparación. Ordena una serie de diccionarios donde cada diccionario incluye un número en una clave "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;
}];
El código anterior pasa por el trabajo de obtener un valor entero para cada clave de clasificación y compararlos, como una ilustración de cómo hacerlo. Dado que los objetos NSNumber
implementan un método de comparación, se podría reescribir mucho más simplemente:
#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];
}];
o el cuerpo del comparador podría incluso ser destilado a 1 línea:
return [[obj1 objectForKey: SORT_KEY] compare: [obj2 objectForKey: SORT_KEY]];
Tiendo a preferir sentencias simples y muchas variables temporales porque el código es más fácil de leer y más fácil de depurar. El compilador optimiza las variables temporales de todos modos, por lo que no hay ninguna ventaja para la versión de todo en una línea.
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)
Utiliza NSSortDescriptor para ordenar un NSMutableArray con objetos personalizados
NSSortDescriptor *sortingDescriptor;
sortingDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
ascending:YES];
NSArray *sortArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];
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
Ordenar usando NSComparator
Si queremos ordenar objetos personalizados, debemos proporcionar NSComparator
, que se utiliza para comparar objetos personalizados. El bloque devuelve un valor NSComparisonResult
para denotar el orden de los dos objetos. Entonces, para ordenar el array completo, NSComparator
se usa de la siguiente manera.
NSArray *sortedArray = [employeesArray sortedArrayUsingComparator:^NSComparisonResult(Employee *e1, Employee *e2){
return [e1.firstname compare:e2.firstname];
}];
Clasifica utilizando NSSortDescriptor
Supongamos, como ejemplo, que tenemos una matriz que contiene instancias de una clase personalizada, Employee tiene atributos firstname, lastname y age. El siguiente ejemplo ilustra cómo crear un NSSortDescriptor que se puede usar para ordenar los contenidos de la matriz en orden ascendente por la clave de edad.
NSSortDescriptor *ageDescriptor = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES];
NSArray *sortDescriptors = @[ageDescriptor];
NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors];
Ordenar usando comparaciones personalizadas
Los nombres son cadenas, y cuando ordena cadenas para presentarlas al usuario, siempre debe usar una comparación localizada. A menudo, también desea realizar una comparación entre mayúsculas y minúsculas. Aquí viene un ejemplo con (localizedStandardCompare :) para ordenar la matriz por apellido y nombre.
NSSortDescriptor *lastNameDescriptor = [[NSSortDescriptor alloc]
initWithKey:@"lastName" ascending:YES selector:@selector(localizedStandardCompare:)];
NSSortDescriptor * firstNameDescriptor = [[NSSortDescriptor alloc]
initWithKey:@"firstName" ascending:YES selector:@selector(localizedStandardCompare:)];
NSArray *sortDescriptors = @[lastNameDescriptor, firstNameDescriptor];
NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors];
Para referencia y discusión detallada, consulte: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/SortDescriptors/Articles/Creating.html
http://www.ios-blog.co.uk/tutorials/objective-c/how-to-sort-nsarray-with-custom-objects/
-(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 *sort = [[NSSortDescriptor alloc] initWithKey:@"_strPrice"
ascending:sortFlag selector:@selector(localizedStandardCompare:)] ;
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 ...