4
$\begingroup$

Considering we have a list of rules:

lst = {"A" -> {"A1" -> {"a.124" -> "45", "a.125" -> "45"}, 
    "A2" -> "something", 
    "B" -> {"b[1].sqw" -> "true", "b[1].ewq" -> "false", 
      "b[2].tyy" -> "saved", "b[2].bfg" -> "iid:"}, "C" -> "eb9d"}}

Note*: I know that the delimiter is always a point - .

How can I "combine" the keys and make another list of vales having as a result:

res = {"A" -> {"A1" -> {"a" -> {"124" -> "45", 
        "125" -> "45"}}, "A2" -> "something", 
    "B" -> {"b[1]" -> {"sqw" -> "true", "ewq" -> "false"}, 
      "b[2]" -> {"tyy" -> "saved", "bfg" -> "iid:"}}, "C" -> "eb9d"}}

UPDATE

A real data example:

{"crs" -> {"BlueHue" -> "0", "BlueSaturation" -> "0", 
   "CameraProfile" -> "Adobe Standard", "ColorNoiseReduction" -> "25",
    "ColorNoiseReductionDetail" -> "50", "Contrast2012" -> "0", 
   "DefringeGreenHueHi" -> "60", "DefringeGreenHueLo" -> "40", 
   "Exposure2012" -> "+0.45", "GreenHue" -> "0", 
   "GreenSaturation" -> "0", "HasCrop" -> "False", 
   "HasSettings" -> "True", "LuminanceSmoothing" -> "0", 
   "ParametricShadowSplit" -> "25", "ParametricShadows" -> "0", 
   "PostCropVignetteAmount" -> "0", "RedHue" -> "0", 
   "RedSaturation" -> "0", "Saturation" -> "0", 
   "SaturationAdjustmentAqua" -> "0", 
   "SaturationAdjustmentBlue" -> "0", 
   "SaturationAdjustmentGreen" -> "0", 
   "SaturationAdjustmentMagenta" -> "0", 
   "SaturationAdjustmentOrange" -> "0", 
   "SaturationAdjustmentPurple" -> "0", 
   "SaturationAdjustmentRed" -> "0", 
   "SaturationAdjustmentYellow" -> "0", "ShadowTint" -> "0", 
   "Shadows2012" -> "+25", "Sharpness" -> "103", 
   "SplitToningHighlightSaturation" -> "0", 
   "SplitToningShadowSaturation" -> "0", "Temperature" -> "3700", 
   "Tint" -> "+16", "ToneCurveName2012" -> "Medium Contrast", 
   "ToneCurvePV2012" -> 
    "0, 0, 32, 22, 64, 56, 128, 128, 192, 196, 255, 255", 
   "ToneCurvePV2012Blue" -> "0, 0, 255, 255", 
   "ToneCurvePV2012Green" -> "0, 0, 255, 255", 
   "ToneCurvePV2012Red" -> "0, 0, 255, 255", "VignetteAmount" -> "0", 
   "WhiteBalance" -> "As Shot"}, 
 "dc" -> {"creator" -> "unknown", "format" -> "image/jpeg"}, 
 "photoshop" -> {"DateCreated" -> "2014-04-28T14:52:32"}, 
 "xmp" -> {"CreateDate" -> "2014-04-28T14:52:32", 
   "CreatorTool" -> "Adobe Photoshop Lightroom 5.0 (Macintosh)", 
   "MetadataDate" -> "2014-04-28T16:11:27-05:00", 
   "ModifyDate" -> "2014-04-28T16:11:27-05:00", "Rating" -> "5"}, 
 "xmpMM" -> {"DerivedFrom" -> {"DerivedFrom.documentID" -> 
      "45DA984AC12B4C2E29FD2841B1732B26", 
     "DerivedFrom.originalDocumentID" -> 
      "45DA984AC12B4C2E29FD2841B1732B26"}, 
   "DocumentID" -> "xmp.did:8669ed4e-bda9-48dd-80cd-4fd3aeef1e06", 
   "History" -> {"History[1].action" -> "derived", 
     "History[1].parameters" -> 
      "converted from image/x-canon-cr2 to image/jpeg, saved to new \
location", "History[2].action" -> "saved", 
     "History[2].instanceID" -> 
      "xmp.iid:8669ed4e-bda9-48dd-80cd-4fd3aeef1e06", 
     "History[2].when" -> "2014-04-28T16:00:23-05:00", 
     "History[2].softwareAgent" -> 
      "Adobe Photoshop Lightroom 5.0 (Macintosh)", 
     "History[2].changed" -> "/", "History[3].action" -> "saved", 
     "History[3].instanceID" -> 
      "xmp.iid:6c92b810-3d29-4c6c-8565-a7f150f0eb9d", 
     "History[3].when" -> "2014-04-28T16:11:27-05:00", 
     "History[3].softwareAgent" -> "Adobe Photoshop CC (Macintosh)", 
     "History[3].changed" -> "/"}, 
   "InstanceID" -> "xmp.iid:6c92b810-3d29-4c6c-8565-a7f150f0eb9d", 
   "OriginalDocumentID" -> "45DA984AC12B4C2E29FD2841B1732B26"}}
$\endgroup$
3
$\begingroup$

Here is one way:

splitAndGroup[list_List]:=Module[{splitedList},
    splitedList=MapAt[StringSplit[#,"."]&,list,{All,1}];
    Normal@GroupBy[splitedList,(#[[1,1]]&),MapAt[Last,{All,1}]]
]

convert[list_List]:=Map[splitAndGroup,lst,{-3}]

Now using:

lst = {
   "A" -> {"A1" -> {"a.124" -> "45", "a.125" -> "45"}, 
   "A2" -> "something", 
   "B" -> {"b[1].sqw" -> "true", "b[1].ewq" -> "false", 
      "b[2].tyy" -> "saved", "b[2].bfg" -> "iid:"},
   "C" -> "eb9d"}
}

You can do convert@lst to get:

   {
     "A"->{"A1"->{"a"->{124->45,125->45}},
     "A2"->"something",
     "B"->{"b[1]"->{"sqw"->"true","ewq"->"false"},
           "b[2]"->{"tyy"->"saved","bfg"->"iid:"}}
    ,"C"->"eb9d"}
   }

And if you need it in Association form:

Needs["GeneralUtilities`"]
ToAssociations@convert@lst

 <|
  "A"-><|"A1"-><|"a"-><|"124"->"45","125"->"45"|>|>,
  "A2"->"something",
  "B"-><|"b[1]"-><|"sqw"->"true","ewq"->"false"|>,
         "b[2]"-><|"tyy"->"saved","bfg"->"iid:"|>|>,
  "C"->"eb9d"|>
 |>

Update

For the real case, there are lists that should not be splited. Like this one:

"dc" -> {"creator" -> "unknown", "format" -> "image/jpeg"}

Just add a If in splitAndGroup, like this:

splitAndGroup[list_List]:=Module[{splitedList},
    splitedList=MapAt[StringSplit[#,"."]&,list,{All,1}];
    If[Length@splitedList[[1,1]]==1,Return@list];
    Normal@GroupBy[splitedList,(#[[1,1]]&),MapAt[Last,{All,1}]]
]
$\endgroup$
  • $\begingroup$ Thanks for the great answer! I have posted an update with a real data that I use. Your function gives a strange result for that data. Could you please comment? Thanks! $\endgroup$ – SuTron May 8 '15 at 14:37
  • 1
    $\begingroup$ @SuTron I believe now it works as you expect. $\endgroup$ – Murta May 8 '15 at 14:50
  • $\begingroup$ You are a Genius! :) $\endgroup$ – SuTron May 8 '15 at 14:53
  • 1
    $\begingroup$ @SuTron glad in help! $\endgroup$ – Murta May 8 '15 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.