包含具有重复值的字典的字典组数组

Posted

技术标签:

【中文标题】包含具有重复值的字典的字典组数组【英文标题】:Group Array of Dictionaries containing Dictionaries with Duplicate Values 【发布时间】:2020-03-23 18:39:34 【问题描述】:

我目前正在开发一个分组的 tableView。我让它工作但想将我的传入数组更改为字典以在 tableview 中提供更多有用的信息。 DictionaryHolder 具有所有不同的键,即名称,它包含一个带有“mainTheme”键的字典,其中一些主键匹配,我想将这些匹配的字典编译成数组,然后用新键“subThemes”编译回一个新字典字典集的数组是否包含“mainTheme”的匹配项...我碰壁了,不知道如何解决这个问题,哪种方法最快,因为有时可能会创建和排序很多字典。任何帮助将不胜感激!

-(NSMutableArray*)themesDictFromThemesPlists:(NSMutableArray*)allThemesonDevice

NSMutableDictionary *compiledThemesDictionaryHolder = [[NSMutableDictionary alloc]init];
NSMutableArray *returnedDict = [[NSMutableArray alloc]init];
NSMutableDictionary *mainThemeCompiled = [[NSMutableDictionary alloc]init];
NSMutableDictionary *themePlistDict = nil;
NSString *packageName= nil;
NSString*fullPlistStr = nil;
NSString *themeStringToDeconstruct = nil;


//create dictionary for each theme
NSMutableArray *allPckgNames = [[NSMutableArray alloc]init];
for (NSString *actualName in allThemesonDevice) 

    themeStringToDeconstruct = actualName;
    if ([themeStringToDeconstruct hasSuffix:@".theme"]) 
        themeStringToDeconstruct = [themeStringToDeconstruct stringByReplacingOccurrencesOfString:@".theme" withString:@""];
    
    themeStringToDeconstruct = [themeStringToDeconstruct stringByReplacingOccurrencesOfString:@"_" withString:@" "];
    NSArray *theWords = [themeStringToDeconstruct componentsSeparatedByString:@" "];
    NSString *nameWithoutTags = [theWords objectAtIndex:0];
    //NSLog (@"ICONOMATIC OBJECT AT INDEX 0 %@",newName);


    fullPlistStr = [NSString stringWithFormat:@"/Library/Themes/%@/Info.plist",actualName];
    themePlistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:fullPlistStr];
    packageName = [themePlistDict objectForKey:@"PackageName"];
    //NSLog (@"ThemePlistDict: %@",themePlistDict);
    //NSLog (@"ICONOMATIC Actual Name : %@ PackageName: %@",actualName,packageName);


    if (packageName) 

        NSMutableDictionary *compiledTheme = [[NSMutableDictionary alloc]init];
        [compiledTheme setValue:actualName forKey:@"fullThemeName"];
        [compiledTheme setValue:nameWithoutTags forKey:@"themeName"];
        [compiledTheme setValue:packageName forKey:@"mainTheme"];

        //can add more icons
        if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat:@"/Library/Themes/%@/icon.png",actualName]]) 
            [compiledTheme setValue:[NSString stringWithFormat:@"/Library/Themes/%@/icon.png",actualName]  forKey:@"icon1"];

        

        NSLog (@"Iconomatic ADD compiledTheme %@ ",compiledTheme);

        [compiledThemesDictionaryHolder setValue:compiledTheme forKey:actualName];
        //[compiledThemesDictionaryHolder addObject:compiledTheme];


        [allPckgNames addObject:packageName];



 



NSLog (@"Iconomatic compiledThemesDictionaryHolder %@ ",compiledThemesDictionaryHolder);

NSLog (@"Iconomatic ALLPckgs: %@",allPckgNames);



/*create Main Dictionary for each package
 This is where Ive hit a wall. I need to determine which dictionaries have matching     
"mainTheme" keysValues and compile into array of dictionaries to store in new dictionary   
(mainThemeCompiled) which will be added into returnDict which is a array that populates the 
tableview by keys*/

 //NSSet or descriptorByKeys I don't know how to approach this
//NSMutableArray *tempStorage = [[NSMutableArray alloc]init];

for (NSDictionary *themeDict in compiledThemesDictionaryHolder) 

    NSLog (@"Iconomatic themeDict: %@",themeDict);

    [mainThemeCompiled setValue:themeDict forKey:@"package"];
   


NSLog(@"Iconomatic compiledThemesDictionaryHolder %@",returnedDict);


return returnedDict;
 




    Iconomatic compiledThemesDictionaryHolder 
   "Bohemic NOIR alt.theme" =     
    fullThemeName = "Bohemic NOIR alt.theme";
    icon1 = "/Library/Themes/Bohemic NOIR alt.theme/icon.png";
    mainTheme = BohemicNOIR;
    themeName = Bohemic;
   ;
    "Bohemic NOIR badges.theme" =     
    fullThemeName = "Bohemic NOIR badges.theme";
    icon1 = "/Library/Themes/Bohemic NOIR badges.theme/icon.png";
    mainTheme = BohemicNOIR;
    themeName = Bohemic;
   ;
   "Bohemic NOIR iPad calendar.theme" =     
    fullThemeName = "Bohemic NOIR iPad calendar.theme";
    icon1 = "/Library/Themes/Bohemic NOIR iPad calendar.theme/icon.png";
    mainTheme = BohemicNOIR;
    themeName = Bohemic;
   ;
   "Bohemic NOIR mask" =     
    fullThemeName = "Bohemic NOIR mask";
    icon1 = "/Library/Themes/Bohemic NOIR mask/icon.png";
    mainTheme = BohemicNOIR;
    themeName = Bohemic;
  ;

【问题讨论】:

命名NSMutableArray *returnedDict = [[NSMutableArray alloc]init];,这是个坏主意。 returnedDicts(带有“s”)可能会稍微好一些,但仍然如此。你能缩进你的代码吗?也许创建子方法,因为我认为//create dictionary for each theme 部分增加了复杂性,并不是真正需要的。另外,我强烈建议使用自定义对象而不是NSDictionary,任何键中的错误都会被破坏。你能显示简单的输入和预期的输出吗? 这是有用的输入。我承认我的命名约定有时可能有点古怪,尽管我知道它的含义并且每个生命周期只使用一次 IK 更改为更合适的名称。我将研究使用自定义对象,我通常会在对象未知时使用,但在我的情况下,我确切地知道它们将永远是什么,除非它们为空。我已经更新了我的答案,现在可以正常工作了。谢谢 【参考方案1】:

好的,这就是我的整体解决方案。主要问题是确定字典数组中可用的匹配对象,并通过使用 indexOfObjectsPassingTest 和 enumerateIndexesUsingBlock 解决

 -(NSMutableArray*)themesDictFromThemesPlists:(NSMutableArray*)allThemesonDevice

NSMutableArray *compiledThemesDictionaryHolder = [[NSMutableArray alloc]init];
NSMutableArray *returnedArrayOfDicts = [[NSMutableArray alloc]init];
NSMutableDictionary *themePlistDict = nil;
NSString *packageName= nil;
NSString*fullPlistStr = nil;


//create dictionary for each theme
NSMutableArray *allPckgNames = [[NSMutableArray alloc]init];
for (NSString *actualName in allThemesonDevice) 

    fullPlistStr = [NSString stringWithFormat:@"/Library/Themes/%@/Info.plist",actualName];
    themePlistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:fullPlistStr];
    packageName = [themePlistDict objectForKey:@"PackageName"];
    //NSLog (@"ThemePlistDict: %@",themePlistDict);
    //NSLog (@"ICONOMATIC Actual Name : %@ PackageName: %@",actualName,packageName);


    if (packageName) 

        NSMutableDictionary *compiledTheme = [[NSMutableDictionary alloc]init];
        [compiledTheme setValue:actualName forKey:@"fullThemeName"];
        [compiledTheme setValue:packageName forKey:@"mainTheme"];

        if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat:@"/Library/Themes/%@/Icon.png",actualName]]) 
            [compiledTheme setValue:[NSString stringWithFormat:@"/Library/Themes/%@/Icon.png",actualName]  forKey:@"icon1"];
            [compiledTheme setValue:@"prominate" forKey:@"prominate"];
            //can add more icons to dict
        
        if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat:@"/Library/Themes/%@/icon.png",actualName]]) 
            [compiledTheme setValue:[NSString stringWithFormat:@"/Library/Themes/%@/icon.png",actualName]  forKey:@"icon1"];
            //can add more icons to dict

        
        //NSLog (@"Iconomatic ADD compiledTheme %@ ",compiledTheme);

        //these arrays below should have same indexes to objects but (allPackgNames) can easliy be grouped
        [compiledThemesDictionaryHolder addObject:compiledTheme];

        [allPckgNames addObject:packageName];


    


 //NSLog (@"Iconomatic compiledThemesDictionaryHolder %@ ",compiledThemesDictionaryHolder);
// NSLog (@"Iconomatic ALLPckgs: %@",allPckgNames);



//create Main Dictionary for each package
NSMutableArray *tempNameArrayToSort = [[NSMutableArray alloc]initWithArray:allPckgNames];
int mainThemesIndex = 0;
for (NSString *mainThemeName in tempNameArrayToSort) 

    NSMutableDictionary *mainThemeDict = [[NSMutableDictionary alloc]init];

    //check for pckg name. Array may contain several matches so remove those at end of loop
    if ([allPckgNames containsObject:mainThemeName]) 

        //gather index set of any matches
        NSIndexSet *indxs = [compiledThemesDictionaryHolder indexesOfObjectsPassingTest:^BOOL(NSDictionary *dict, NSUInteger idx, BOOL *stop) 
            return ([dict[@"mainTheme"]isEqualToString:mainThemeName]);
        ];
        //NSLog(@"Iconomatic indexSet %@",indxs);

        //enumerate those index sets to grab dictionaries and store in (subThemes)
        NSMutableArray *subThemeArray = [[NSMutableArray alloc]init];
        [indxs enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) 
            // NSLog(@"Iconomatic dict %@ at index %lu",[compiledThemesDictionaryHolder objectAtIndex:idx],idx);
            [subThemeArray addObject:[compiledThemesDictionaryHolder objectAtIndex:idx]];
        ];


        //start creating mainDictionary for MainTheme

        NSDictionary *themeDict = [compiledThemesDictionaryHolder objectAtIndex:mainThemesIndex];
        NSString *fullThemeName = [themeDict objectForKey:@"fullThemeName"];

        NSLog (@"ICONOMATIC BUILD~ MainTheme: %@ Dict: %@ subThemes: %@",mainThemeName,themeDict,subThemeArray);

        [mainThemeDict setValue:fullThemeName forKey:@"fullThemeName"];
        [mainThemeDict setValue:[themeDict objectForKey:@"mainTheme"] forKey:@"themeName"];

        UIImage *icon1 = nil;
        UIImage *icon2 = nil;
        UIImage *icon3 = nil;
        UIImage *icon4 = nil;

        if ([subThemeArray count] >=1) 

            [mainThemeDict setValue:subThemeArray forKey:@"themesSubThemes"];
            [mainThemeDict setValue:[NSNumber numberWithInt:[subThemeArray count]] forKey:@"themeSubCount"];

            for (NSDictionary *subDict in subThemeArray) 


                NSString *mainthemeIcons = [NSString stringWithFormat:@"/Library/Themes/%@/IconBundles",[subDict objectForKey:@"fullThemeName"]];

                if ([subDict objectForKey:@"prominate"]) 

                    icon1 = [UIImage imageWithContentsOfFile:[subDict objectForKey:@"icon1"]];

                    if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat:@"%@/com.apple.AppStore-large.png",mainthemeIcons]]) 

                        icon1 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.AppStore-large.png",[subDict objectForKey:@"fullThemeName"]]];
                        icon2 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.Music-large.png",[subDict objectForKey:@"fullThemeName"]]];
                        icon3 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.MobileSMS-large.png",[subDict objectForKey:@"fullThemeName"]]];
                        icon4 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.mobilesafari-large.png",[subDict objectForKey:@"fullThemeName"]]];

                    

                else

                    if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat:@"%@/com.apple.AppStore-large.png",mainthemeIcons]]) 

                        icon1 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.AppStore-large.png",[subDict objectForKey:@"fullThemeName"]]];
                        icon2 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.Music-large.png",[subDict objectForKey:@"fullThemeName"]]];
                        icon3 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.MobileSMS-large.png",[subDict objectForKey:@"fullThemeName"]]];
                        icon4 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.mobilesafari-large.png",[subDict objectForKey:@"fullThemeName"]]];
                    
                
            
        
        //nosubthemes
        else
            if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat:@"%@/com.apple.AppStore-large.png",fullThemeName]]) 

                icon1 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.AppStore-large.png",fullThemeName]];
                icon2 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.Music-large.png",fullThemeName]];
                icon3 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.MobileSMS-large.png",fullThemeName]];
                icon4 = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/com.apple.mobilesafari-large.png",fullThemeName]];
            

        



        if (icon1) 
            [mainThemeDict setValue:icon1  forKey:@"icon1"];
        
        if (icon2) 
            [mainThemeDict setValue:icon2  forKey:@"icon2"];
        
        if (icon3) 
            [mainThemeDict setValue:icon3  forKey:@"icon3"];
        
        if (icon4) 
            [mainThemeDict setValue:icon4  forKey:@"icon4"];
        



        if ([activeIconomaticThemes containsObject:fullThemeName]) 
            [mainThemeDict setValue:[NSNumber numberWithBool:YES] forKey:@"isActive"];
        
        else
            [mainThemeDict setValue:[NSNumber numberWithBool:NO] forKey:@"isActive"];
        


        [allPckgNames removeObject:mainThemeName];
        //end of creating mainThemeDict
    

    mainThemesIndex = mainThemesIndex+1;

    if ([mainThemeDict count]) 
        [returnedArrayOfDicts addObject:mainThemeDict];
    
    //end of (mainTheme in allPackNames)



NSLog(@"Iconomatic returnedArrayOfDicts %@",returnedArrayOfDicts);

return returnedArrayOfDicts;

现在主要主题的输出是

 ICONOMATIC BUILD~ MainTheme: Lotus Dark Dict: 
fullThemeName = "Lotus Dark Apps";
mainTheme = "Lotus Dark";
  subThemes: (
    
    fullThemeName = "Lotus Dark Apps";
    mainTheme = "Lotus Dark";
,
    
    fullThemeName = "Lotus Dark Apps (Alternate)";
    mainTheme = "Lotus Dark";
,
    
    fullThemeName = "Lotus Dark Calendar";
    mainTheme = "Lotus Dark";
,
    
    fullThemeName = "Lotus Dark Icon Effect";
    mainTheme = "Lotus Dark";
,
    
    fullThemeName = "Lotus Dark Mask";
    mainTheme = "Lotus Dark";
,
    
    fullThemeName = "Lotus Dark Settings";
    mainTheme = "Lotus Dark";
,
    
    fullThemeName = "Lotus Dark Widgets";
    mainTheme = "Lotus Dark";

 )

最后是:

  Iconomatic returnedArrayOfDicts (
    
    fullThemeName = "Bohemic NOIR alt.theme";
    icon1 = "<UIImage:0x281f48b40 anonymous 300, 300>";
    icon2 = "<UIImage:0x281f5f9f0 anonymous 300, 300>";
    icon3 = "<UIImage:0x281f5fba0 anonymous 300, 300>";
    icon4 = "<UIImage:0x281f5fcc0 anonymous 300, 300>";
    isActive = 1;
    themeName = BohemicNOIR;
    themeSubCount = 7;
    themesSubThemes =         (
                    
            fullThemeName = "Bohemic NOIR alt.theme";
            icon1 = "/Library/Themes/Bohemic NOIR alt.theme/icon.png";
            mainTheme = BohemicNOIR;
        ,
                    
            fullThemeName = "Bohemic NOIR badges.theme";
            icon1 = "/Library/Themes/Bohemic NOIR badges.theme/icon.png";
            mainTheme = BohemicNOIR;
        ,

【讨论】:

以上是关于包含具有重复值的字典的字典组数组的主要内容,如果未能解决你的问题,请参考以下文章

Pandas:如何将具有重复索引值的数据框转换为字典

如何从IOS中的字典数组中删除重复性? [关闭]

从字典中添加具有映射值的新熊猫列[重复]

搜索特定值的嵌套字典列表[重复]

如何在没有可选值的情况下将字典数组快速转换为json字符串[重复]

删除python中字典值的重复项