Подтвердить что ты не робот

Перестроить NSArray, группируя объекты с соответствующими номерами идентификаторов?

У меня есть NSArray, и каждый объект в массиве имеет имя groupId и имя. Каждый объект уникален, но есть много с одинаковым идентификатором groupId. Есть ли способ, которым я могу разделить массив и перестроить его так, чтобы имена были сгруппированы в один объект с соответствующим groubId? Вот как выглядит массив:

2013-03-12 20:50:05.572 appName[4102:702] the  array:  (
        {
        groupId = 1;
        name = "Dan";
    },
        {
        groupId = 1;
        name = "Matt";
    },
        {
        groupId = 2;
        name = "Steve";
    },
        {
        groupId = 2;
        name = "Mike";
    },
        {
        groupId = 3;
        name = "John";

    },
        {
        groupId = 4;
        name = "Kevin";
    }
)

Вот что мне хотелось бы выглядеть так:

2013-03-12 20:50:05.572 appName[4102:702] the  array:  (
        {
        groupId = 1;
        name1 = "Dan";
        name2 = "Matt";
    },
        {
        groupId = 2;
        name1 = "Steve";
        name2 = "Mike";
    },
        {
        groupId = 3;
        name = "John";

    },
        {
        groupId = 4;
        name = "Kevin";
    }
)

EDIT: Я пробовал и терпел неудачу с множеством попыток, большинство из которых было похоже на это (небрежный отдых, но чтобы дать представление):

int idNum = 0;
for (NSDictionary *arrObj in tempArr){
    NSString *check1 = [NSString stringWithFormat:@"%@",[arrObj valueForKey:@"groupId"]];
    NSString *check2 = [NSString stringWithFormat:@"%@",[[newDict valueForKey:@"groupId"]];
    if (check1 == check2){
        NSString *nameStr = [NSString stringWithFormat:@"name_%d",idNum];
        [newDict setValue:[arrObj valueForKey:@"name"] forKey:nameStr];
    }
    else {
        [newDict setValue:arrObj forKey:@"object"];
    }
    idNum++;
}  
4b9b3361

Ответ 1

NSArray *array = @[@{@"groupId" : @"1", @"name" : @"matt"},
                   @{@"groupId" : @"2", @"name" : @"john"},
                   @{@"groupId" : @"3", @"name" : @"steve"},
                   @{@"groupId" : @"4", @"name" : @"alice"},
                   @{@"groupId" : @"1", @"name" : @"bill"},
                   @{@"groupId" : @"2", @"name" : @"bob"},
                   @{@"groupId" : @"3", @"name" : @"jack"},
                   @{@"groupId" : @"4", @"name" : @"dan"},
                   @{@"groupId" : @"1", @"name" : @"kevin"},
                   @{@"groupId" : @"2", @"name" : @"mike"},
                   @{@"groupId" : @"3", @"name" : @"daniel"},
                   ];

NSMutableArray *resultArray = [NSMutableArray new];
NSArray *groups = [array valueForKeyPath:@"@distinctUnionOfObjects.groupId"];
for (NSString *groupId in groups)
{
    NSMutableDictionary *entry = [NSMutableDictionary new];
    [entry setObject:groupId forKey:@"groupId"];

    NSArray *groupNames = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"groupId = %@", groupId]];
    for (int i = 0; i < groupNames.count; i++)
    {
        NSString *name = [[groupNames objectAtIndex:i] objectForKey:@"name"];
        [entry setObject:name forKey:[NSString stringWithFormat:@"name%d", i + 1]];
    }
    [resultArray addObject:entry];
}

NSLog(@"%@", resultArray);

Вывод:

    (
        {
        groupId = 3;
        name1 = steve;
        name2 = jack;
        name3 = daniel;
    },
        {
        groupId = 4;
        name1 = alice;
        name2 = dan;
    },
        {
        groupId = 1;
        name1 = matt;
        name2 = bill;
        name3 = kevin;
    },
        {
        groupId = 2;
        name1 = john;
        name2 = bob;
        name3 = mike;
    }
 )

Ответ 2

Это требует NSDictionary NSArrays. Там нет быстрого и элегантного способа - вам придется прокручивать источник.

NSMutableDictionary *d = [NSMutableDictionary dictionaryWithCapacity:10]; //Or use alloc/init
for(SomeObject o in appname) //What the type of objects? you tell me
{
    NSObject *ID = [o objectForKey: @"groupId"];
    NSMutableArray *a = [d objectForKey: ID];
    if(a == nil)
    {
        a = [NSMutableArray arrayWithCapacity: 10];
        [d setObject:a forKey: ID];
    }
    [a addObject: [o objectForKey: @"name"]];
}

EDIT: отредактировано, чтобы не предполагать тип данных ключа.

Ответ 3

Это похоже на ответ Seva, но он может быть добавлен как метод категории в NSArray:

/// @return A dictionary of NSMutableArrays
- (NSDictionary *)abc_groupIntoDictionary:(id<NSCopying>(^)(id object))keyFromObjectCallback {
    NSParameterAssert(keyFromObjectCallback);
    NSMutableDictionary *result = [NSMutableDictionary dictionary];
    for (id object in self) {
        id<NSCopying> key = keyFromObjectCallback(object);
        NSMutableArray *array = [result objectForKey:key];
        if (array == nil) {
            array = [NSMutableArray new];
            [result setObject:array forKey:key];
        }
        [array addObject:object];
    }
    return [result copy];
}

И вы можете использовать его так:

NSDictionary *groups = [people abc_groupIntoDictionary:^id<NSCopying>(NSDictionary *person) {
    return person[@"groupId"];
}];

Это не совсем то же самое, что и исходный ответ, поскольку он сохранит словарь пользователя в качестве значений в массиве, но вы можете просто просто прочитать свойство name.

Ответ 4

Быстрая реализация ответа Сергея для моих друзей-нобов.

class People: NSObject {
    var groupId: String
    var name : String
    init(groupId: String, name: String){
        self.groupId = groupId
        self.name = name
    }
}


let matt = People(groupId: "1", name: "matt")
let john = People(groupId: "2", name: "john")
let steve = People(groupId: "3", name: "steve")
let alice = People(groupId: "4", name: "alice")
let bill = People(groupId: "1", name: "bill")
let bob = People(groupId: "2", name: "bob")
let jack = People(groupId: "3", name: "jack")
let dan = People(groupId: "4", name: "dan")
let kevin = People(groupId: "1", name: "kevin")
let mike = People(groupId: "2", name: "mike")
let daniel = People(groupId: "3", name: "daniel")

let arrayOfPeople = NSArray(objects: matt, john, steve, alice, bill, bob, jack, dan, kevin, mike, daniel)

var resultArray = NSMutableArray()
let groups = arrayOfPeople.valueForKeyPath("@distinctUnionOfObjects.groupId") as [String]


for groupId in groups {
    var entry = NSMutableDictionary()
    entry.setObject(groupId, forKey: "groupId")
    let predicate = NSPredicate(format: "groupId = %@", argumentArray: [groupId])
    var groupNames = arrayOfPeople.filteredArrayUsingPredicate(predicate)
    for i in 0..<groupNames.count {
        let people = groupNames[i] as People
        let name = people.name
        entry.setObject(name, forKey: ("name\(i)"))
    }
    resultArray.addObject(entry)
}

println(resultArray)

Обратите внимание на знак @в значенииForKeyPath. это немного подтолкнуло меня:)

Ответ 5

Следующий код будет перестроить NSArray, сгруппировав объекты w.r.t с любыми соответствующими ключами в каждом словаре в этом массиве

//only to a take unique keys. (key order should be maintained)
NSMutableArray *aMutableArray = [[NSMutableArray alloc]init];

NSMutableDictionary *dictFromArray = [NSMutableDictionary dictionary];

for (NSDictionary *eachDict in arrOriginal) {
  //Collecting all unique key in order of initial array
  NSString *eachKey = [eachDict objectForKey:@"roomType"];
  if (![aMutableArray containsObject:eachKey]) {
   [aMutableArray addObject:eachKey];
  }

  NSMutableArray *tmp = [grouped objectForKey:key];
  tmp  = [dictFromArray objectForKey:eachKey];

 if (!tmp) {
    tmp = [NSMutableArray array];
    [dictFromArray setObject:tmp forKey:eachKey];
 }
[tmp addObject:eachDict];

}

//NSLog(@"dictFromArray %@",dictFromArray);
//NSLog(@"Unique Keys :: %@",aMutableArray);

// Преобразование из словаря в массив снова...

self.finalArray = [[NSMutableArray alloc]init];
for (NSString *uniqueKey in aMutableArray) {
   NSDictionary *aUniqueKeyDict = @{@"groupKey":uniqueKey,@"featureValues":[dictFromArray objectForKey:uniqueKey]};
   [self.finalArray addObject:aUniqueKeyDict];
}

Надеюсь, что это может помочь.