olvido - poner clave iphone 6
NSDiccionario con claves ordenadas (9)
Tengo curiosidad si esta es una situación en la que otras personas se han encontrado. Tengo un NSDictionary (almacenado en un plist) que básicamente estoy usando como una matriz asociativa (cadenas como claves y valores). Quiero utilizar el conjunto de claves como parte de mi aplicación, pero me gustaría que estén en un orden específico (no es realmente un orden en el que pueda escribir un algoritmo para ordenarlas). Siempre pude almacenar una matriz separada de las teclas, pero parece una especie de tonto porque siempre tendría que actualizar las claves del diccionario, así como los valores de la matriz, y asegurarse de que siempre se correspondan. Actualmente solo uso [myDictionary allKeys], pero obviamente esto los 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?
Implementación mínima de una subclase ordenada de NSDictionary (basada en https://github.com/nicklockwood/OrderedDictionary ). Siéntase libre de extender para 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]);
}
La solución de tener un NSMutableArray asociado de claves no es tan malo. Evita la subclasificación de NSDictionary, y si tiene cuidado al escribir accesos, no debería ser demasiado difícil mantenerla sincronizada.
Llego tarde al juego con una respuesta real, pero podría interesarte investigar CHOrderedDictionary . Es una subclase de NSMutableDictionary que encapsula otra estructura para mantener el orden de las teclas. (Es parte de CHDataStructures.framework ). Encuentro que es 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 otros que enfrentan este problema.
Mi pequeña adición: ordenando con la 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]];
}
No existe un método incorporado del que pueda adquirir esto. Pero una simple lógica funciona para ti. Simplemente puede agregar algunos textos numéricos al frente 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 el 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.
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 clasifican automáticamente en la inserción. Funciona sorprendentemente bien con los tipos escalares u objetos Objective-C como claves y como valores.
Si necesita incluir una matriz como valor, solo use std::vector
lugar de NSArray
.
Una advertencia es que es posible que desee proporcionar su propia función insert_or_assign
, a menos que pueda usar C ++ 17 (vea esta respuesta ). Además, debe typedef
los tipos para evitar ciertos errores de compilación. Una vez que descubra cómo usar std::map
, iterators, etc., es bastante sencillo y rápido.
Rápido y sucio
Cuando necesite ordenar su diccionario (en este documento llamado "myDict"), haga esto:
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 de índice * 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 ...
Si va a subclase NSDictionary, debe implementar estos métodos como mínimo:
- NSDictionary
-
-count
-
-objectForKey:
-
-keyEnumerator
-
- NSMutableDictionary
-
-removeObjectForKey:
-
-setObject:forKey:
-
- NSCopying / NSMutableCopying
-
-copyWithZone:
-
-mutableCopyWithZone:
-
- NSCoding
-
-encodeWithCoder:
-
-initWithCoder:
-
- NSFastEnumeration (para Leopard)
-
-countByEnumeratingWithState:objects:count:
-
La forma más fácil 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 concebir omitir la implementación de -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 ordenadas.
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)