Friday, January 28, 2022

#1 2021-10-20 03:42:21 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1218

Flatten a dictionary of dictionaries

I've been working on a project and I've reached a sticking point. I have a dictionary that contains both key-value pairs and nested dictionaries, as in the following:

{|{tiff}|:{YResolution:144.0, ResolutionUnit:2, XResolution:144.0}, |{exif}|:{PixelXDimension:2640, PixelYDimension:2068, UserComment:"Screenshot"}, ProfileName:"DELL P2415Q", DPIWidth:144.0, PixelHeight:2068, DPIHeight:144.0, ColorModel:"RGB", Depth:8, HasAlpha:true, |{png}|:{InterlaceType:0, XPixelsPerMeter:5669, YPixelsPerMeter:5669}, PixelWidth:2640}

I need to flatten the dictionary to the following:

{YResolution:144.0, ResolutionUnit:2, XResolution:144.0, PixelXDimension:2640, PixelYDimension:2068, UserComment:"Screenshot", ProfileName:"DELL P2415Q", DPIWidth:144.0, PixelHeight:2068, DPIHeight:144.0, ColorModel:"RGB", Depth:8, HasAlpha:true, InterlaceType:0, XPixelsPerMeter:5669, YPixelsPerMeter:5669, PixelWidth:2640}

The key names of the nested dictionaries (e.g. |{tiff}|) varies from one running of the script to another. Thanks


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#2 2021-10-20 05:15:16 pm

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5475

Re: Flatten a dictionary of dictionaries

Hi peavine.

Applescript:

use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
use scripting additions

set aDictionary to current application's class "NSDictionary"'s dictionaryWithDictionary:({|{tiff}|:{YResolution:144.0, ResolutionUnit:2, XResolution:144.0}, |{exif}|:{PixelXDimension:2640, PixelYDimension:2068, UserComment:"Screenshot"}, ProfileName:"DELL P2415Q", DPIWidth:144.0, PixelHeight:2068, DPIHeight:144.0, ColorModel:"RGB", Depth:8, HasAlpha:true, |{png}|:{InterlaceType:0, XPixelsPerMeter:5669, YPixelsPerMeter:5669}, PixelWidth:2640})

set newDictionary to current application's class "NSMutableDictionary"'s new()
set theKeys to aDictionary's allKeys()
repeat with thisKey in theKeys
   set thisObject to (aDictionary's valueForKey:(thisKey))
   if (thisObject's isKindOfClass:(current application's class "NSDictionary")) then
       tell newDictionary to addEntriesFromDictionary:(thisObject)
   else
       tell newDictionary to setValue:(thisObject) forKey:(thisKey)
   end if
end repeat

newDictionary


NG

Offline

 

#3 2021-10-20 07:06:20 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1218

Re: Flatten a dictionary of dictionaries

Thanks Nigel--that works great. I spent over an hour on this and came close but the part I couldn't figure out was 'isKindOfClass:(current application's class "NSDictionary"'.


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#4 2021-10-21 03:31:09 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5475

Re: Flatten a dictionary of dictionaries

Hi peavine.

Yeah. isKindOfClass: is an NSObject "protocol" (according to Shane's book) which tells you whether or not the object's a member of a class umbrella'd by the specified class, so the code should work even if the object's actually an NSMutableDictionary or some non-public NSDictionary subclass.

The parameter has to be a class specifier, but of course the specifier doesn't have to be in my preferred style. It can just be isKindOfClass:(current application's NSDictionary).


NG

Offline

 

#5 2021-10-21 09:12:21 am

Fredrik71
Member
Registered: 2019-10-23
Posts: 929

Re: Flatten a dictionary of dictionaries

@Nigel, thanks smile

I made a handel to make it more useful in a library.

Applescript:

use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
use scripting additions

set theDict to ({|{tiff}|:{YResolution:144.0, ResolutionUnit:2, XResolution:144.0}, |{exif}|:{PixelXDimension:2640, PixelYDimension:2068, UserComment:"Screenshot"}, ProfileName:"DELL P2415Q", DPIWidth:144.0, PixelHeight:2068, DPIHeight:144.0, ColorModel:"RGB", Depth:8, HasAlpha:true, |{png}|:{InterlaceType:0, XPixelsPerMeter:5669, YPixelsPerMeter:5669}, PixelWidth:2640})

(its dictionaryWithNestedDictionary:theDict) as record

on dictionaryWithNestedDictionary:theDict
   set mutableDict to current application's NSMutableDictionary's new()
   set theDict to current application's NSDictionary's dictionaryWithDictionary:theDict
   set theKeys to theDict's allKeys()
   repeat with thisKey in theKeys
       set thisObject to (theDict's valueForKey:thisKey)
       if (thisObject's isKindOfClass:(current application's NSDictionary)) then
           tell mutableDict to addEntriesFromDictionary:(thisObject)
       else
           tell mutableDict to setValue:(thisObject) forKey:(thisKey)
       end if
   end repeat
   return mutableDict
end dictionaryWithNestedDictionary:


if you are the expert, who will you call if its not your imagination.

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)