IT TIP

정렬 된 키가있는 NSDictionary

itqueen 2020. 10. 12. 21:21
반응형

정렬 된 키가있는 NSDictionary


기본적으로 연관 배열 (키와 값으로 문자열)로 사용중인 NSDictionary (plist에 저장 됨)가 있습니다. 응용 프로그램의 일부로 키 배열을 사용하고 싶지만 특정 순서 (정렬 알고리즘을 작성할 수있는 순서가 아님)로 지정하고 싶습니다. 나는 항상 별도의 키 배열을 저장할 수 있지만, 항상 사전의 키와 배열의 값을 업데이트하고 항상 일치하는지 확인해야했기 때문에 다소 까다로워 보입니다. 현재는 [myDictionary allKeys] 만 사용하고 있지만 분명히 임의의 비 보장 순서로 반환합니다. Objective-C에 누락 된 데이터 구조가 있습니까? 누구든지 이것을 더 우아하게 수행하는 방법에 대한 제안이 있습니까?


연관된 NSMutableArray 키를 갖는 솔루션은 그렇게 나쁘지 않습니다. NSDictionary의 서브 클래 싱을 피하고 접근 자 작성에주의를 기울이면 동기화를 유지하는 것이 너무 어렵지 않아야합니다.


실제 답변으로 게임에 늦었지만 CHOrderedDictionary 조사에 관심이있을 수 있습니다 . 키 순서를 유지하기위한 또 다른 구조를 캡슐화하는 NSMutableDictionary의 하위 클래스입니다. ( CHDataStructures.framework 의 일부입니다 .) 딕셔너리와 배열을 별도로 관리하는 것보다 더 편리하다고 생각합니다.

공개 : 이것은 내가 작성한 오픈 소스 코드입니다. 이 문제에 직면 한 다른 사람들에게 유용 할 수 있기를 바랍니다.


이것을 얻을 수있는 내장 된 방법은 없습니다. 그러나 간단한 논리가 작동합니다. 사전을 준비하는 동안 각 키 앞에 숫자 텍스트를 몇 개만 추가하면됩니다. 처럼

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

이제 모든 키를 배치 한 순서대로 가져 오는 동안 sortingArrayUsingSelector를 사용할 수 있다면.

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

UIView에서 키를 표시하려는 위치에서 앞의 3 개 문자를 잘라냅니다.


NSDictionary를 하위 클래스로 만들려면 최소한 다음 메서드를 구현해야합니다.

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

원하는 작업을 수행하는 가장 쉬운 방법은 조작하는 자체 NSMutableDictionary와 정렬 된 키 세트를 저장하는 NSMutableArray를 포함하는 NSMutableDictionary의 하위 클래스를 만드는 것입니다.

당신이 당신의 객체를 인코딩하기 위해가는 일은 없습니다 경우 구현 건너 생각할 수 -encodeWithCoder:-initWithCoder:

위의 10 개 메서드의 모든 메서드 구현은 호스팅 된 사전 또는 순서가 지정된 키 배열을 통해 직접 이동합니다.


내 작은 추가 사항 : 숫자 키로 정렬 (작은 코드에 대한 속기 표기 사용)

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

그런 다음 사전을 주문해야 할 때 색인을 만듭니다.

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

이제 * index 객체는 올바른 순서로 적절한 키를 포함합니다. 이 솔루션은 모든 키가 반드시 존재해야하는 것은 아니며, 우리가 다루는 일반적인 상황입니다.


For, Swift 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 기반 ). 필요에 따라 자유롭게 확장하십시오.

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

목표 -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 ++를별로 좋아하지 않지만 제가 점점 더 많이 사용하고있는 한 가지 해결책은 Objective-C ++와 std::map표준 템플릿 라이브러리를 사용하는 것입니다. 삽입시 키가 자동으로 정렬되는 사전입니다. 스칼라 유형이나 Objective-C 객체 모두 키와 값으로 놀랍도록 잘 작동합니다.

배열을 값으로 포함해야하는 경우 std::vector대신을 사용하십시오 NSArray.

One caveat is that you might want to provide your own insert_or_assign function, unless you can use C++17 (see this answer). Also, you need to typedef your types to prevent certain build errors. Once you figure out how to use std::map, iterators etc., it is pretty straightforward and fast.

참고URL : https://stackoverflow.com/questions/376090/nsdictionary-with-ordered-keys

반응형