Ich habe ein NSDictionary (in einer Plist gespeichert), das ich grundsätzlich als assoziatives Array verwende (Zeichenfolgen als Schlüssel und Werte). Ich möchte das Array von Schlüsseln als Teil meiner Anwendung verwenden, möchte aber, dass sie in einer bestimmten Reihenfolge vorliegen (nicht wirklich eine Reihenfolge, in die ich einen Algorithmus schreiben kann, um sie zu sortieren). Ich könnte immer ein separates Array der Schlüssel speichern, aber das scheint ziemlich klug zu sein, da ich immer die Schlüssel des Wörterbuchs sowie die Werte des Arrays aktualisieren und sicherstellen müsste, dass sie immer übereinstimmen. Momentan verwende ich nur [myDictionary allKeys], aber dies gibt sie offensichtlich in einer willkürlichen, nicht garantierten Reihenfolge zurück. Gibt es eine Datenstruktur in Objective-C, die mir fehlt? Hat jemand irgendwelche Vorschläge, wie man dies eleganter macht?
Die Lösung, über ein NSMutableArray von Schlüsseln zu verfügen, ist nicht so schlecht. Es wird vermieden, NSDictionary in Unterklassen zu unterteilen, und wenn Sie mit dem Schreiben von Accessoren vorsichtig sind, sollte es nicht zu schwierig sein, die Synchronisation aufrechtzuerhalten.
Ich bin zu spät zum Spiel mit einer tatsächlichen Antwort, aber Sie könnten interessiert sein, CHOrderedDictionary zu untersuchen. Es ist eine Unterklasse von NSMutableDictionary, die eine andere Struktur zur Aufrechterhaltung der Schlüsselreihenfolge enthält. (Es ist Teil von CHDataStructures.framework .) Ich finde es praktischer, als ein Wörterbuch und ein Array getrennt zu verwalten.
Offenlegung: Dies ist Open-Source-Code, den ich geschrieben habe. Ich hoffe nur, dass es für andere nützlich sein kann, die sich diesem Problem gegenübersehen.
Es gibt keine solche eingebaute Methode, von der Sie dies erwerben können. Aber eine einfache logische Arbeit für Sie. Während Sie das Wörterbuch vorbereiten, können Sie einfach einige numerische Zeichen vor jeder Taste einfügen. Mögen
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];
Jetzt können Sie sortingArrayUsingSelector verwenden, während Sie alle Schlüssel in der Reihenfolge erhalten, in der Sie sie platziert haben.
NSArray *arr = [[dict allKeys] sortedArrayUsingSelector:@selector(localizedStandardCompare:)];
An der Stelle, an der Sie die Tasten in UIView anzeigen möchten, hacken Sie einfach die vorderen 3 Zeichen ab.
Wenn Sie eine Unterklasse von NSDictionary erstellen möchten, müssen Sie mindestens die folgenden Methoden implementieren:
-count
-objectForKey:
-keyEnumerator
-removeObjectForKey:
-setObject:forKey:
-copyWithZone:
-mutableCopyWithZone:
-encodeWithCoder:
-initWithCoder:
-countByEnumeratingWithState:objects:count:
Der einfachste Weg, das zu tun, was Sie wollen, besteht darin, eine Unterklasse von NSMutableDictionary zu erstellen, die ihr eigenes NSMutableDictionary enthält, das sie manipuliert, und ein NSMutableArray, um einen geordneten Satz von Schlüsseln zu speichern.
Wenn Sie Ihre Objekte nie codieren werden, können Sie die Implementierung von -encodeWithCoder:
Und -initWithCoder:
Möglicherweise überspringen.
Alle Ihre Methodenimplementierungen in den obigen 10 Methoden würden dann entweder direkt durch Ihr gehostetes Wörterbuch oder Ihr bestelltes Schlüsselarray gehen.
Mein kleiner Zusatz: Sortieren nach Zifferntasten (Verwenden von Kurzschreibweisen für kleineren Code)
// 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]];
}
Schnell und schmutzig:
Wenn Sie Ihr Wörterbuch (im Folgenden "myDict" genannt) bestellen müssen, gehen Sie folgendermaßen vor:
NSArray *ordering = [NSArray arrayWithObjects: @"Thing",@"OtherThing",@"Last Thing",nil];
Wenn Sie dann Ihr Wörterbuch bestellen müssen, erstellen Sie einen Index:
NSEnumerator *sectEnum = [ordering objectEnumerator];
NSMutableArray *index = [[NSMutableArray alloc] init];
id sKey;
while((sKey = [sectEnum nextObject])) {
if ([myDict objectForKey:sKey] != nil ) {
[index addObject:sKey];
}
}
Jetzt enthält das * index-Objekt die entsprechenden Schlüssel in der richtigen Reihenfolge. Beachten Sie, dass für diese Lösung nicht unbedingt alle Schlüssel vorhanden sein müssen. Dies ist die übliche Situation, mit der wir es zu tun haben ...
Für, Swift. Bitte probieren Sie den folgenden Ansatz aus
//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)
Minimale Implementierung einer geordneten Unterklasse von NSDictionary (basierend auf https://github.com/nicklockwood/OrderedDictionary ). Fühlen Sie sich frei, um für Ihre Bedürfnisse zu verlängern:
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)
}
}
}
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) }
@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
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]);
}
Ich mag C++ nicht besonders, aber eine Lösung, die ich immer häufiger verwende, ist die Verwendung von Objective-C++ und std::map
aus der Standardvorlagenbibliothek. Es ist ein Wörterbuch, dessen Schlüssel beim Einfügen automatisch sortiert werden. Es funktioniert überraschend gut mit skalaren Typen oder Objective-C-Objekten sowohl als Schlüssel als auch als Werte.
Wenn Sie ein Array als Wert einfügen müssen, verwenden Sie einfach std::vector
anstelle von NSArray
.
Eine Einschränkung ist, dass Sie möglicherweise Ihr eigenes insert_or_assign
Funktion, es sei denn, Sie können C++ 17 verwenden (siehe diese Antwort ). Außerdem müssen Sie Ihre Typen typedef
, um bestimmte Erstellungsfehler zu vermeiden. Sobald Sie herausgefunden haben, wie Sie std::map
, Iteratoren usw., es ist ziemlich einfach und schnell.