NSDictionary与有序的键

我很好奇,如果这是其他人已经发现自己的情况。我有一个NSDictionary(存储在一个plist),我基本上使用作为关联数组(string作为键和值)。 我想使用键的数组作为我的应用程序的一部分,但我希望他们是在一个特定的顺序(不是一个顺序,我可以写一个algorithm来sorting)。 我总是可以存储一个单独的键的数组,但是这似乎有点奇怪,因为我总是必须更新字典的键以及数组的值,并确保它们始终相对应。 目前我只使用[myDictionary allKeys],但显然这是以任意的,无保证的顺序返回它们。 Objective-C中是否有一个数据结构,我错过了? 有没有人有任何build议,如何更优雅地做到这一点?

有一个关联NSMutableArray的键的解决scheme并不是那么糟糕。 它避免了NSDictionary的子类化,如果你仔细的写访问器,保持同步不应该太难。

我迟到了,但是你可能有兴趣去研究CHOrderedDictionary 。 它是NSMutableDictionary的一个子类,封装了用于维护键sorting的另一个结构。 (这是CHDataStructures.framework的一部分。)我发现它比单独pipe理字典和数组更方便。

披露:这是我写的开源代码。 只是希望对面临这个问题的其他人有用。

没有这样的内部方法可以从中获得这个。 但一个简单的逻辑工作给你。 在准备词典时,您可以在每个键的前面简单地添加几个数字文本。 喜欢

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]; 

现在,如果您可以使用sortedArrayUsingSelector同时获取所有键在您放置的顺序。

 NSArray *arr = [[dict allKeys] sortedArrayUsingSelector:@selector(localizedStandardCompare:)]; 

在你想在UIView中显示按键的地方,只要切掉前面的3个字符。

如果你打算inheritanceNSDictionary,你至less需要实现这些方法:

  • 的NSDictionary
    • -count
    • -objectForKey:
    • -keyEnumerator
  • 的NSMutableDictionary
    • -removeObjectForKey:
    • -setObject:forKey:
  • NSCopying / NSMutableCopying
    • -copyWithZone:
    • -mutableCopyWithZone:
  • NSCoding
    • -encodeWithCoder:
    • -initWithCoder:
  • NSFastEnumeration (用于Leopard)
    • -countByEnumeratingWithState:objects:count:

做你想做的最简单的方法是做一个NSMutableDictionary的子类,它包含它自己操作的NSMutableDictionary和一个NSMutableArray来存储一组有序的键。

如果你永远不会编码你的对象,你可以设想跳过-encodeWithCoder:-encodeWithCoder: -initWithCoder:

上述10个方法中的所有方法实现将直接通过托pipe字典或您的有序密钥数组。

我的小添加:按数字键sorting(对较小的代码使用速记符号)

 // 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]]; } 

快速'肮脏:

当你需要命令你的字典(这里称为“myDict”)时,执行以下操作:

  NSArray *ordering = [NSArray arrayWithObjects: @"Thing",@"OtherThing",@"Last Thing",nil]; 

然后,当你需要订购你的字典时,创build一个索引:

  NSEnumerator *sectEnum = [ordering objectEnumerator]; NSMutableArray *index = [[NSMutableArray alloc] init]; id sKey; while((sKey = [sectEnum nextObject])) { if ([myDict objectForKey:sKey] != nil ) { [index addObject:sKey]; } } 

现在,* index对象将以正确的顺序包含适当的键。 请注意,这个解决scheme并不需要所有的密钥都必须存在,这是我们正在处理的通常情况。

因为,斯威夫特3 。 请尝试以下方法

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

NSDictionary的有序子类最小的实现(基于https://github.com/nicklockwood/OrderedDictionary )。 随意扩展您的需求:

斯威夫特3和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) } } } 

用法

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

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

用法

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

我不太喜欢C ++,但是我看到自己使用越来越多的解决scheme是使用标准模板库中的Objective-C ++和std::map 。 这是一个字典,其键在插入时自动sorting。 无论是标量types还是Objective-C对象,它都可以很好地用作键和值。

如果你需要包含一个数组作为一个值,只需使用std::vector而不是NSArray

一个警告是,你可能想要提供你自己的insert_or_assign函数,除非你可以使用C ++ 17(见这个答案 )。 此外,你需要键入你的types,以防止某些构build错误。 一旦你弄清楚如何使用std::map ,迭代器等等,它是非常直接和快速的。