如何将具有相同属性的所有字典从数组中获取到新数组?

Posted

技术标签:

【中文标题】如何将具有相同属性的所有字典从数组中获取到新数组?【英文标题】:How to get all dictionaries with some same attributes from an array to a new array? 【发布时间】:2014-10-22 00:39:01 【问题描述】:

这是我的要求:

forSaleSingleProperties数组应该包含没有相同属性PARCELID的字典

forSaleMultipleProperties数组应该包含具有相同属性PARCELID的那些字典的数组

forSalePropertiesArray 是包含所有 dict 的基本数组。

注意:字典包含各种其他属性。我想要所有具有相同PARCELID 属性的人

我不明白这个逻辑有什么问题......

if (_forSaleSinglePropertiesArray==nil) 
    _forSaleSinglePropertiesArray = [[NSMutableArray alloc]initWithObjects: nil];


if (_forSaleMultiplePropertiesArray==nil) 
    _forSaleMultiplePropertiesArray = [[NSMutableArray alloc]initWithObjects: nil];


if (_forSalePropertiesArray!=nil) 
    if (_forSalePropertiesArray.count>1) 
        BOOL propertyObject1IsMultiple = NO;
        NSDictionary *propertyObject1;
        NSMutableArray *multiplePinArray = [[NSMutableArray alloc]initWithObjects: nil];
        for (int i=0; i<_forSalePropertiesArray.count; i++) 
            propertyObject1 = [_forSalePropertiesArray objectAtIndex:i];
            multiplePinArray = nil;
            multiplePinArray = [[NSMutableArray alloc]initWithObjects: nil];
            for (int j=i+1; j<_forSalePropertiesArray.count; j++) 
                NSDictionary *propertyObject2 = [_forSalePropertiesArray objectAtIndex:j];
                if ([propertyObject1 valueForKey:PARCEL_ID]==[propertyObject2 valueForKey:PARCEL_ID]) 
                    if (_forSaleMultiplePropertiesArray.count==0) 
                        [multiplePinArray addObject:propertyObject2];
                        propertyObject1IsMultiple = YES;
                        [_forSaleMultiplePropertiesArray addObject:multiplePinArray];
                    else
                        BOOL propFound = NO;
                        NSMutableArray *propArr;
                        NSInteger index = -1;
                        for(NSMutableArray *arr in _forSaleMultiplePropertiesArray)
                            if (![arr containsObject:propertyObject2]&&!propFound) 
                                [arr addObject:propertyObject2];
                                propertyObject1IsMultiple = YES;
                                propFound = YES;
                                index = [_forSaleMultiplePropertiesArray indexOfObject:arr];
                                propArr = [[NSMutableArray alloc]initWithArray:arr];
                            
                        
                        if (propArr!=nil) 
                            [_forSaleMultiplePropertiesArray replaceObjectAtIndex:index withObject:propArr];
                        
                    
                
            
            if (!propertyObject1IsMultiple) 
                [_forSaleSinglePropertiesArray addObject:propertyObject1];
            
        
    

【问题讨论】:

那是一些非常丑陋的代码。 您应该可以使用NSSet 和/或NSPredicate 对数据进行过滤和分组***.com/questions/1439564/… Dat 代码虽然...复杂性。如果。循环。哇。让我试着解决这个问题。我认为(根据标题)我可以在大约 10 行内完成...呵呵:D 同意它的丑陋代码,这就是我来这里的原因,只是需要一个更简单的机制 【参考方案1】:

好吧……

我将把它作为占位符。

    按 PARCELID 对父数组进行排序。

    迭代数组。

    分成两堆。

...什么的。以后再写吧。

【讨论】:

我喜欢你的想法,所以我实现了它。但无法将其缩短到 10 行。【参考方案2】:

我会做得更像这样:

- (void)solution 
    self.forSaleSinglePropertiesArray = [[NSMutableArray alloc] init];
    self.forSaleMultiplePropertiesArray = [[NSMutableArray alloc] init];

    NSDictionary *partitionedProperties = partitionPropertiesByParcelID(self.forSalePropertiesArray);
    [self dividePropertiesIntoSingleAndMultiple:partitionedProperties];


NSDictionary *partitionPropertiesByParcelID(NSArray *properties) 
    NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
    for (NSDictionary *property in properties) 
        id parcelID = property[PARCEL_ID];
        NSMutableArray *parcels = result[parcelID];
        if (parcels == nil) 
            parcels = [[NSMutableArray alloc] init];
            [result setObject:parcels forKey:parcelID];
        
        [parcels addObject:property];
    
    return result;


- (void)dividePropertiesIntoSingleAndMultiple:(NSDictionary *)partitionedProperties 
    for (NSArray *properties in partitionedProperties.allValues) 
        if (properties.count == 1) 
            [self.forSaleSinglePropertiesArray addObject:properties[0]];
        
        else 
            assert(properties.count > 1);
            [self.forSaleMultiplePropertiesArray addObject:properties];
        
    

首先,代码创建一个字典,其中键是宗地 ID,值是具有该宗地 ID 的属性数组。然后它会遍历该字典并将每个宗地 ID 的代表放入单个或多个数组中。

我觉得这段代码更容易理解,我强烈怀疑如果你对上面的代码和你的答案做性能指标,这段代码在大数据集上会有更好的性能。我相信这是真的,因为你的答案似乎有 O(n^2) 的表现,而我的答案是 O(n)。 (如果您不确定这是什么意思,请阅读“Big-O notation”。)

另外,您确定您的答案确实适用于所有数据集吗?在迭代数组时从数组中删除对象会在我的书中抛出一个巨大的危险信号。

【讨论】:

【参考方案3】:

我非常喜欢@Fogmeister 的排序想法,我实现了它:

- (void)sortSolultion 
    self.forSaleSinglePropertiesArray = [[NSMutableArray alloc] init];
    self.forSaleMultiplePropertiesArray = [[NSMutableArray alloc] init];

    NSArray *forSaleArray = [self.forSalePropertiesArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) 
        return [obj1[PARCEL_ID] compare:obj2[PARCEL_ID]];
    ];
    id currentParcelID = nil;
    self.propertiesWithCurrentParcelID = [[NSMutableArray alloc] init];
    for (NSDictionary *property in forSaleArray) 
        if (self.propertiesWithCurrentParcelID.count == 0) 
            currentParcelID = property[PARCEL_ID];
        
        else if (![property[PARCEL_ID] isEqual: currentParcelID]) 
            [self placeCurrentPropertiesInCorrectArray];
            currentParcelID = property[PARCEL_ID];
        
        [self.propertiesWithCurrentParcelID addObject:property];
    
    [self placeCurrentPropertiesInCorrectArray];


- (void)placeCurrentPropertiesInCorrectArray 
    if (self.propertiesWithCurrentParcelID.count > 1) 
        [self.forSaleMultiplePropertiesArray addObject:self.propertiesWithCurrentParcelID];
    
    else if (self.propertiesWithCurrentParcelID.count == 1) 
        [self.forSaleSinglePropertiesArray addObject:self.propertiesWithCurrentParcelID[0]];
    
    [self.propertiesWithCurrentParcelID removeAllObjects];

这个解决方案的圈复杂度比我之前的解决方案略高,而且确实比我的第一个解决方案更难让它没有错误。但是此解决方案具有较小的分配空间。两者似乎都具有相同的大 O 复杂度。

【讨论】:

【参考方案4】:

好吧,我自己做对了。

将代码更新为以下更简单和快速的机制:

if (_forSaleSinglePropertiesArray==nil) 
    _forSaleSinglePropertiesArray = [[NSMutableArray alloc]initWithObjects: nil];

if (_forSaleMultiplePropertiesArray==nil) 
    _forSaleMultiplePropertiesArray = [[NSMutableArray alloc]initWithObjects: nil];

if (_forSalePropertiesArray!=nil) 
    NSMutableDictionary *samePropsDict = [[NSMutableDictionary alloc]init];
    for (NSDictionary* dict in _forSalePropertiesArray) 
        NSMutableArray *samePropsArray = [samePropsDict objectForKey:[dict valueForKey:PARCEL_ID]];
        if (samePropsArray==nil) 
            samePropsArray = [[NSMutableArray alloc]init];
        
        [samePropsArray addObject:dict];
        [samePropsDict setObject:samePropsArray forKey:[dict valueForKey:PARCEL_ID]];
    
    for (NSString *key in [samePropsDict allKeys]) 
        NSArray *arr = [samePropsDict objectForKey:key];
        if (arr.count>1) 
            [_forSaleMultiplePropertiesArray addObject:arr];
        else
            [_forSaleSinglePropertiesArray addObject:[arr firstObject]];
        
    

【讨论】:

仅供参考。以上将失败,定义如下的三个属性数组:@[propertyWithParcelID1, propertyWithParcelID2, propertyWithParcelID1]。它永远不会找到单个属性。 我更新了代码以找到它,现在即使对于单个属性也可以正常工作 也编辑上面的代码。我今天就你的问题发表演讲,看看你如何实现你的算法会有所帮助。 它仍然失败,原因相同。 @[propertyWithParcelID1, propertyWithParcelID2, propertyWithParcelID1] 应该以单个属性数组@[propertyWithParcelID2] 中的一个属性和多属性数组@[[propertyWIthParcelID1, propertyWithParcelID1]] 中的一个包含两个属性的数组结束。它成功地将两个属性放入了 multiplePropertyArray,但它丢失了应该放入单个属性数组中的属性。 如果你坚持要从你正在迭代的数组中删除对象,你将不得不比现在更加小心。

以上是关于如何将具有相同属性的所有字典从数组中获取到新数组?的主要内容,如果未能解决你的问题,请参考以下文章

如何比较字典值中的多个数组,并将每个数组元素的字典键映射到新数组/列表中

如何从获取请求数组结果中构建字典?

对象数组的对象。获取具有相同属性的所有值的长度

使用循环从 plist 的根级别获取字典数组并将其放入变量中

Pandas - 如何将属性保存到数组中并将它们的值保存到新列中

想要从 iPhone 的 plist 中的字典数组中获取数据? [复制]