1
$\begingroup$

I have nested associations like this:

<|{"Country1","YEAR1"} -> {<|{"VARIABLE1", "MEASURE1"} -> 
 "Value1"|>, <|{"VARIABLE2", "MEASURE2"} -> "Value2"|>}, {"Country1",
"YEAR2"} -> {<|{"VARIABLE1", "MEASURE1"} -> 
 "Value1"|>, <|{"VARIABLE2", "MEASURE2"} -> "Value2"|>}, {"Country2", 
"YEAR1"} -> {<|{"VARIABLE1", "MEASURE1"} -> 
 "Value1"|>, <|{"VARIABLE2", "MEASURE2"} -> "Value2"|>},{"Country2", 
"YEAR2"} -> {<|{"VARIABLE1", "MEASURE1"} -> 
 "Value1"|>, <|{"VARIABLE2", "MEASURE2"} -> "Value2"|>}

and so on...Is there a way to select all Values e.g. for Country1 and for all Years but lets say only for the (sub)Key {"VARIABLE1", "MEASURE1"} for these Years? More specifically, the desired output would be a list like this

{Country1, YEAR1, Value1},{Country1, YEAR2, Value1}

Many thanks for you comments!

$\endgroup$
1
$\begingroup$

With the data form you provided this seems to work:

aData = <|{"Country1", 
     "YEAR1"} -> {<|{"VARIABLE1", "MEASURE1"} -> 
       "Value1"|>, <|{"VARIABLE2", "MEASURE2"} -> 
       "Value2"|>}, {"Country1", 
     "YEAR2"} -> {<|{"VARIABLE1", "MEASURE1"} -> 
       "Value1"|>, <|{"VARIABLE2", "MEASURE2"} -> 
       "Value2"|>}, {"Country2", 
     "YEAR1"} -> {<|{"VARIABLE1", "MEASURE1"} -> 
       "Value1"|>, <|{"VARIABLE2", "MEASURE2"} -> 
       "Value2"|>}, {"Country2", 
     "YEAR2"} -> {<|{"VARIABLE1", "MEASURE1"} -> 
       "Value1"|>, <|{"VARIABLE2", "MEASURE2"} -> "Value2"|>}|>;

m = {"VARIABLE1", "MEASURE1"};

c = "Country1";

Map[Append[#, Association[aData[#]][m]] &, Keys[KeySelect[aData, MemberQ[#, c] &]]]

(* {{"Country1", "YEAR1", "Value1"}, {"Country1", "YEAR2", "Value1"}} *)

Update

I need to select the variables for five specific countries. Another point would be if it is possible to further select only specific years (e.g. only from Year 5 to Year 10)

We make an appropriate criteria for KeySelect.

c = {"Country1"};

y = {"YEAR1"};

Map[Append[#, Association[aData[#]][m]] &, 
 Keys[KeySelect[aData, 
   Length[Intersection[#, c]] > 0 && 
     Length[Intersection[#, y]] > 0 &]]]

(* {{"Country1", "YEAR1", "Value1"}} *)
| improve this answer | |
$\endgroup$
  • $\begingroup$ Thats very nice - many thanks for that! But in your solution both countries are included. This was just an easy code to illustrate my problem. In reality I have 20 Countries for 15 Years or so. And I need to select the variables for five specific countries. Another point would be if it is possible to further select only specific years (e.g. only from Year 5 to Year 10) $\endgroup$ – M.A. Apr 19 '18 at 20:52
  • $\begingroup$ @M.A. Ok I fixed the code. With KeySelect you make selection of the keys that have the countries and years you want to focus on. $\endgroup$ – Anton Antonov Apr 19 '18 at 21:11
  • $\begingroup$ That is nearly perfect. But what if "m" is a list with multiple Variable-Measure combinations? I could solve this with a table but is there a more elegant way to obtain {"Country1", "YEAR1", "Value1", "Value2", "ValueX"} ? $\endgroup$ – M.A. Apr 22 '18 at 19:47
  • $\begingroup$ @M.A. If m is a list of lists you can use Map or Table over m (as you say). "[...] but is there a more elegant way to obtain {"Country1", "YEAR1", "Value1", "Value2", "ValueX"} ?" -- I am not sure what do you mean by "more elegant" in the context of your data. You can always define a function for the extraction and your code will/can/might look elegant with it. $\endgroup$ – Anton Antonov Apr 22 '18 at 20:17
  • $\begingroup$ When i am using a table like this: Table[Map[Append[#, Association[aData[#]][m[[i]]]] &, Keys[KeySelect[aData, Length[Intersection[#, c]] > 0 && Length[Intersection[#, y]] > 0 &]]],{i,1,Length[m]}] i will obtain {"Country1", "YEAR1", "Value1"},{"Country1", "YEAR1", "Value2"}, and so on... Now I could manipulate that output to obtain {"Country1", "YEAR1", "Value1", "Value2", "ValueX"} but maybe there is a way to obtain that directly? $\endgroup$ – M.A. Apr 23 '18 at 7:52
1
$\begingroup$

Maybe you would benefit from a change of your data structure.

1. A more nested association

Given your initial set:

aData=<|
{"Country1","YEAR1"}->{<|{"VARIABLE1","MEASURE1"}->"Value111"|>,<|{"VARIABLE2","MEASURE2"}->"Value112"|>},
{"Country1","YEAR2"}->{<|{"VARIABLE1","MEASURE1"}->"Value121"|>,<|{"VARIABLE2","MEASURE2"}->"Value122"|>},
{"Country2","YEAR1"}->{<|{"VARIABLE1","MEASURE1"}->"Value211"|>,<|{"VARIABLE2","MEASURE2"}->"Value212"|>},
{"Country2","YEAR2"}->{<|{"VARIABLE1","MEASURE1"}->"Value221"|>,<|{"VARIABLE2","MEASURE2"}->"Value222"|>}|>;

let's turn it into:

newd = KeyValueMap[
   Association[#1[[1]] -> Association[#1[[2]] -> #2]] &, 
   Merge[#, Identity] & /@ aData] // Merge[#, Join @@ # &] &

<|"Country1" -> <|"YEAR1" -> <|{"VARIABLE1", "MEASURE1"} -> {"Value111"}, {"VARIABLE2", "MEASURE2"} -> {"Value112"}|>, "YEAR2" -> <|{"VARIABLE1", "MEASURE1"} -> {"Value121"}, {"VARIABLE2", "MEASURE2"} -> {"Value122"}|>|>, "Country2" -> <|"YEAR1" -> <|{"VARIABLE1", "MEASURE1"} -> {"Value211"}, {"VARIABLE2", "MEASURE2"} -> {"Value212"}|>, "YEAR2" -> <|{"VARIABLE1", "MEASURE1"} -> {"Value221"}, {"VARIABLE2", "MEASURE2"} -> {"Value222"}|>|>|>

then you can make more readable query like that:

res=newd[[{"Country2", "Country1"}, {"YEAR1", "YEAR2"}, Key@{"VARIABLE1", "MEASURE1"}]]

<|"Country2" -> <|"YEAR1" -> {"Value211"}, "YEAR2" -> {"Value221"}|>, "Country1" -> <|"YEAR1" -> {"Value111"}, "YEAR2" -> {"Value121"}|>|>

and to get the output you want:

Level[MapIndexed[Join /* RotateLeft, res, {2}], {2}] /. Key -> Identity

{{"Country2", "YEAR1", "Value211"}, {"Country2", "YEAR2", "Value221"}, {"Country1", "YEAR1", "Value111"}, {"Country1", "YEAR2", "Value121"}}

2. A Flat association

But why not try a flat association ?

flat = Flatten@
  Table[<|"Country" -> "C" <> ToString@i, 
    "Year" -> "Y" <> ToString@j, 
    "VarMeas" -> "VM" <> ToString@k|>, {i, 2}, {j, 2}, {k, 2}]

{ <|Country->C1,Year->Y1,VarMeas->VM1|>, <|Country->C1,Year->Y1,VarMeas->VM2|>, <|Country->C1,Year->Y2,VarMeas->VM1|>, <|Country->C1,Year->Y2,VarMeas->VM2|>, <|Country->C2,Year->Y1,VarMeas->VM1|>, <|Country->C2,Year->Y1,VarMeas->VM2|>, <|Country->C2,Year->Y2,VarMeas->VM1|>, <|Country->C2,Year->Y2,VarMeas->VM2|>}

Then

Query[
Select[
(MemberQ[{"C1", "C2"}, #Country] && MemberQ[{"Y1"}, #Year]) &
], 
{"Country", "Year", "VarMeas"}]@flat // Values

{{"C1", "Y1", "VM1"}, {"C1", "Y1", "VM2"}, {"C2", "Y1", "VM1"},{"C2","Y1", "VM2"}}

| improve this answer | |
$\endgroup$
  • $\begingroup$ but it is not the output OP wanted. $\endgroup$ – Kuba Apr 20 '18 at 10:14
  • $\begingroup$ @Kuba Right. I updated my answer. $\endgroup$ – SquareOne Apr 20 '18 at 11:29
  • $\begingroup$ @SquareOne: Thats also very nice but for my purpose it is better to keep the "main" key in the form {CountryX, YearX}; So I can add new (unknown) variables with "Merge" if it is necessary. Its about adding specific country-year variables from different .xls lists so this form seems to me most apropriate $\endgroup$ – M.A. Apr 22 '18 at 19:29

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.