Tengo un NSDictionary (almacenado en un plist) que básicamente estoy usando como una matriz asociativa (cadenas como claves y valores). Quiero usar la matriz de claves como parte de mi aplicación, pero me gustaría que estuvieran en un orden específico (no realmente un orden en el que pueda escribir un algoritmo para ordenarlas). Siempre podría almacenar una matriz separada de las claves, pero eso parece un poco complicado porque siempre tendría que actualizar las claves del diccionario, así como los valores de la matriz, y asegurarme de que siempre correspondan. Actualmente solo uso [myDictionary allKeys], pero obviamente esto las devuelve en un orden arbitrario y no garantizado. ¿Hay una estructura de datos en Objective-C que me falta? ¿Alguien tiene alguna sugerencia sobre cómo hacer esto de manera más elegante?
fuente
Llego tarde al juego con una respuesta real, pero es posible que le interese investigar CHOrderedDictionary . Es una subclase de NSMutableDictionary que encapsula otra estructura para mantener el orden de las claves. (Es parte de CHDataStructures.framework .) Me parece más conveniente que administrar un diccionario y una matriz por separado.
Divulgación: este es el código de fuente abierta que escribí. Solo espero que pueda ser útil para otras personas que enfrentan este problema.
fuente
No existe un método incorporado a partir del cual pueda adquirir esto. Pero una simple lógica funciona para ti. Simplemente puede agregar un poco de texto numérico delante de cada tecla mientras prepara el diccionario. Me gusta
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys: @"01.Created",@"cre", @"02.Being Assigned",@"bea", @"03.Rejected",@"rej", @"04.Assigned",@"ass", @"05.Scheduled",@"sch", @"06.En Route",@"inr", @"07.On Job Site",@"ojs", @"08.In Progress",@"inp", @"09.On Hold",@"onh", @"10.Completed",@"com", @"11.Closed",@"clo", @"12.Cancelled", @"can", nil];
Ahora, si puede usar sortingArrayUsingSelector mientras obtiene todas las claves en el mismo orden en que las coloca.
NSArray *arr = [[dict allKeys] sortedArrayUsingSelector:@selector(localizedStandardCompare:)];
En el lugar donde desea mostrar las teclas en UIView, simplemente corte los 3 caracteres frontales.
fuente
Si va a subclase NSDictionary, debe implementar estos métodos como mínimo:
-count
-objectForKey:
-keyEnumerator
-removeObjectForKey:
-setObject:forKey:
-copyWithZone:
-mutableCopyWithZone:
-encodeWithCoder:
-initWithCoder:
-countByEnumeratingWithState:objects:count:
La forma más sencilla de hacer lo que desea es crear una subclase de NSMutableDictionary que contenga su propio NSMutableDictionary que manipule y un NSMutableArray para almacenar un conjunto ordenado de claves.
Si nunca va a codificar sus objetos, podría omitir la implementación
-encodeWithCoder:
y-initWithCoder:
Todas las implementaciones de sus métodos en los 10 métodos anteriores pasarían directamente a través de su diccionario alojado o su matriz de claves ordenada.
fuente
Mi pequeña adición: ordenar por tecla numérica (usando notaciones abreviadas para códigos más pequeños)
// the resorted result array NSMutableArray *result = [NSMutableArray new]; // the source dictionary - keys may be Ux timestamps (as integer, wrapped in NSNumber) NSDictionary *dict = @{ @0: @"a", @3: @"d", @1: @"b", @2: @"c" }; {// do the sorting to result NSArray *arr = [[dict allKeys] sortedArrayUsingSelector:@selector(compare:)]; for (NSNumber *n in arr) [result addObject:dict[n]]; }
fuente
Rápido y sucio:
Cuando necesite solicitar su diccionario (en adelante denominado "myDict"), haga lo siguiente:
NSArray *ordering = [NSArray arrayWithObjects: @"Thing",@"OtherThing",@"Last Thing",nil];
Luego, cuando necesite ordenar su diccionario, cree un índice:
NSEnumerator *sectEnum = [ordering objectEnumerator]; NSMutableArray *index = [[NSMutableArray alloc] init]; id sKey; while((sKey = [sectEnum nextObject])) { if ([myDict objectForKey:sKey] != nil ) { [index addObject:sKey]; } }
Ahora, el objeto * index contendrá las claves apropiadas en el orden correcto. Tenga en cuenta que esta solución no requiere que todas las claves existan necesariamente, que es la situación habitual con la que nos enfrentamos ...
fuente
Para Swift 3 . Pruebe el siguiente enfoque
//Sample Dictionary let dict: [String: String] = ["01.One": "One", "02.Two": "Two", "03.Three": "Three", "04.Four": "Four", "05.Five": "Five", "06.Six": "Six", "07.Seven": "Seven", "08.Eight": "Eight", "09.Nine": "Nine", "10.Ten": "Ten" ] //Print the all keys of dictionary print(dict.keys) //Sort the dictionary keys array in ascending order let sortedKeys = dict.keys.sorted { $0.localizedCaseInsensitiveCompare($1) == ComparisonResult.orderedAscending } //Print the ordered dictionary keys print(sortedKeys) //Get the first ordered key var firstSortedKeyOfDictionary = sortedKeys[0] // Get range of all characters past the first 3. let c = firstSortedKeyOfDictionary.characters let range = c.index(c.startIndex, offsetBy: 3)..<c.endIndex // Get the dictionary key by removing first 3 chars let firstKey = firstSortedKeyOfDictionary[range] //Print the first key print(firstKey)
fuente
Implementación mínima de una subclase ordenada de NSDictionary (basada en https://github.com/nicklockwood/OrderedDictionary ). No dude en ampliar según sus necesidades:
Swift 3 y 4
class MutableOrderedDictionary: NSDictionary { let _values: NSMutableArray = [] let _keys: NSMutableOrderedSet = [] override var count: Int { return _keys.count } override func keyEnumerator() -> NSEnumerator { return _keys.objectEnumerator() } override func object(forKey aKey: Any) -> Any? { let index = _keys.index(of: aKey) if index != NSNotFound { return _values[index] } return nil } func setObject(_ anObject: Any, forKey aKey: String) { let index = _keys.index(of: aKey) if index != NSNotFound { _values[index] = anObject } else { _keys.add(aKey) _values.add(anObject) } } }
uso
let normalDic = ["hello": "world", "foo": "bar"] // initializing empty ordered dictionary let orderedDic = MutableOrderedDictionary() // copying normalDic in orderedDic after a sort normalDic.sorted { $0.0.compare($1.0) == .orderedAscending } .forEach { orderedDic.setObject($0.value, forKey: $0.key) } // from now, looping on orderedDic will be done in the alphabetical order of the keys orderedDic.forEach { print($0) }
C objetivo
@interface MutableOrderedDictionary<__covariant KeyType, __covariant ObjectType> : NSDictionary<KeyType, ObjectType> @end @implementation MutableOrderedDictionary { @protected NSMutableArray *_values; NSMutableOrderedSet *_keys; } - (instancetype)init { if ((self = [super init])) { _values = NSMutableArray.new; _keys = NSMutableOrderedSet.new; } return self; } - (NSUInteger)count { return _keys.count; } - (NSEnumerator *)keyEnumerator { return _keys.objectEnumerator; } - (id)objectForKey:(id)key { NSUInteger index = [_keys indexOfObject:key]; if (index != NSNotFound) { return _values[index]; } return nil; } - (void)setObject:(id)object forKey:(id)key { NSUInteger index = [_keys indexOfObject:key]; if (index != NSNotFound) { _values[index] = object; } else { [_keys addObject:key]; [_values addObject:object]; } } @end
uso
NSDictionary *normalDic = @{@"hello": @"world", @"foo": @"bar"}; // initializing empty ordered dictionary MutableOrderedDictionary *orderedDic = MutableOrderedDictionary.new; // copying normalDic in orderedDic after a sort for (id key in [normalDic.allKeys sortedArrayUsingSelector:@selector(compare:)]) { [orderedDic setObject:normalDic[key] forKey:key]; } // from now, looping on orderedDic will be done in the alphabetical order of the keys for (id key in orderedDic) { NSLog(@"%@:%@", key, orderedDic[key]); }
fuente
No me gusta mucho C ++, pero una solución que me veo usando cada vez más es usar Objective-C ++ y
std::map
de la biblioteca de plantillas estándar. Es un diccionario cuyas claves se ordenan automáticamente al insertarlas. Funciona sorprendentemente bien con tipos escalares u objetos Objective-C tanto como claves como valores.Si necesita incluir una matriz como valor, use en
std::vector
lugar deNSArray
.Una advertencia es que es posible que desee proporcionar su propia
insert_or_assign
función, a menos que pueda usar C ++ 17 (consulte esta respuesta ). Además, necesitatypedef
sus tipos para evitar ciertos errores de compilación. Una vez que descubra cómo usar losstd::map
iteradores, etc., es bastante sencillo y rápido.fuente