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$

2 Answers 2

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"}} *)
$\endgroup$
7
  • $\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.
    Commented Apr 19, 2018 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$ Commented Apr 19, 2018 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.
    Commented Apr 22, 2018 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$ Commented Apr 22, 2018 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.
    Commented Apr 23, 2018 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"}}

$\endgroup$
3
  • $\begingroup$ but it is not the output OP wanted. $\endgroup$
    – Kuba
    Commented Apr 20, 2018 at 10:14
  • $\begingroup$ @Kuba Right. I updated my answer. $\endgroup$
    – SquareOne
    Commented Apr 20, 2018 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.
    Commented Apr 22, 2018 at 19:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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