it-swarm.com.de

NSDictionary mit bestellten Schlüsseln

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?

78
Andy Bourassa

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.

23
Abizern

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.

19
Quinn Taylor

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.

15

Wenn Sie eine Unterklasse von NSDictionary erstellen möchten, müssen Sie mindestens die folgenden Methoden implementieren:

  • NSDictionary
    • -count
    • -objectForKey:
    • -keyEnumerator
  • NSMutableDictionary
    • -removeObjectForKey:
    • -setObject:forKey:
  • NSCopying/NSMutableCopying
    • -copyWithZone:
    • -mutableCopyWithZone:
  • NSCoding
    • -encodeWithCoder:
    • -initWithCoder:
  • NSFastEnumeration (für Leopard)
    • -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.

7
Ashley Clark

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

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

3
Adam Prall

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)
2
Dinesh

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:

Schnelle 3 und 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)
        }
    }
}

verwendung

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

Ziel c

@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

verwendung

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]);
}
1
Cœur

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.

0
Martin Winter