通过对具有匹配 ID 号的对象进行分组来重建 NSArray?

Posted

技术标签:

【中文标题】通过对具有匹配 ID 号的对象进行分组来重建 NSArray?【英文标题】:Rebuild an NSArray by grouping objects that have matching id numbers? 【发布时间】:2013-03-13 01:37:40 【问题描述】:

我有一个 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";
    
)

编辑: 我已经尝试过很多次但都失败了,大多数都是这样的(草率的娱乐,但给出一个想法):

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

【问题讨论】:

【参考方案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】:

这需要 NSArrays 的 NSDictionary。没有快速而优雅的方法 - 您必须滚动浏览源代码。

NSMutableDictionary *d = [NSMutableDictionary dictionaryWithCapacity:10]; //Or use alloc/init
for(SomeObject o in appname) //What's 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"]];

编辑:编辑为不假定密钥的数据类型。

【讨论】:

NSString *ID = [NSNumber numberWithInt: [o objectForKey: @"groupId"]]; numberWithIntint 作为参数并返回NSNumber。您提供一个id 参数并分配给NSString【参考方案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】:

为我的菜鸟们快速实现 Sergery 的回答。

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)

注意 valueForKeyPath 中的 @ 符号。这让我有点绊倒:)

【讨论】:

【参考方案5】:

下面的代码将重建一个 NSArray,方法是根据该数组中每个字典中的任何匹配键对对象进行分组

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

希望对你有帮助..

【讨论】:

以上是关于通过对具有匹配 ID 号的对象进行分组来重建 NSArray?的主要内容,如果未能解决你的问题,请参考以下文章

通过对它们进行分组来获取重复的 Id

如何在reactjs / javascript中按值对对象数组进行分组

按id typescript对对象数组进行分组[重复]

通过 linq 对实体查询进行分组,以通过加入表来获取具有最新时间戳的一条记录

如何对相同布尔值的块进行分组?

如何根据具有命名空间的唯一元素或 ID 对元素进行排序和分组