3
$\begingroup$

I have a table of the form(the table is very long, i put an example):

 tab1={{{1,10,30},{1,20,54},{1,30,65}},{{2,10,35},{2,20,65},{2,30,70}}}

How can I give index to elements of this table? I would like to have such a rule:

 tab1[x][y][z]

so that I can operate on its elements. For example, I would like to obtain,for every x:

 sum[x]=30+54+65  (*sum of z given x=1*)

And for every y:

 sum[y]=30+35    (*sum of z given y=10*)
$\endgroup$
3
  • 1
    $\begingroup$ Total with level specification? $\endgroup$ Commented Jun 15, 2020 at 9:02
  • 1
    $\begingroup$ I am not able to understand why sum[x]=30+54+65 is sum of z given x=1? How did it know to sum only the third elements in the first list, and not say sum the second elements of the first list? And also sum[y]=30+35 is sum of z given y=10 how? Please try to explain more clearly how these were generated. If there are implicit assumption, then make them explicit. Any way, as was mentioned above, better to just use Total with the proper Part specifications. No need for all this gymnastics just to access parts of lists. Mathematica has good support to access any Part of lists. ? [[ ]] $\endgroup$
    – Nasser
    Commented Jun 15, 2020 at 9:17
  • $\begingroup$ These are given data, in a triplet form whose first, second and third elements are respectively x,y and z. All I want to do is ,for a given x, to sum z's for different y's and, for a given y, sum z's for different x's. $\endgroup$
    – Orion
    Commented Jun 15, 2020 at 9:23

2 Answers 2

3
$\begingroup$

You might consider Dataset for the kind of slicing/dicing you wish to perform:

ds = Dataset[Join @@ MapIndexed[
     AssociationThread[{"class", "group", "x", "y", "z"}, Flatten[{#2, #}]] &, tab1, {2}]]

enter image description here

ds[GroupBy["x"], All, {"y", "z"}]

enter image description here

ds[GroupBy["y"] /* Map[Total], Select[#"x" == 1 &], {"z"}]

enter image description here

We can define a function that takes a predicate, a grouping key, a list of target keys and a function to be applied to the target keys:

ClearAll[foo]
foo[selector_, groupbykey_, keys_List, func_] := 
 ds[GroupBy[groupbykey] /* Map[func], Select[selector], keys]

Examples:

foo[#x == 1 &, "y", {"z"}, Total]

enter image description here

foo[True &, "y", {"z"}, List]

enter image description here

foo[True &, "y", {"z"}, Total]

enter image description here

foo[#z >= 35 &, "x", {"y", "group"}, Mean]

enter image description here

foo[#z >= 35 &, "x", {"y", "group"}, Identity]

enter image description here

foo[#z >= 35 &, "x", {"y", "group"}, bar]

enter image description here

$\endgroup$
2
$\begingroup$

These are given data, in a triplet form whose first, second and third elements are respectively x,y and z. All I want to do is ,for a given x, to sum z's for different y's and, for a given y, sum z's for different x's.

In that case, why do you care about having them as list of list of lists? You could Flatten them at 1 and just do

sum[label_, value_, list_List] := Module[{r},

  (*assumes list has the form {{x,y,z},{x,y,z},...,{x,y,z}}*)

  r = Which[label == "x",
    Cases[list, {value, _, _}],
    label == "y",
    Cases[list, {_, value, _}],
    label == "z",
    Cases[list, {_, _, value}]
    ];
  Total[r[[All, 3]]]
  ];

Call it as

tab1 = {{{1, 10, 30}, {1, 20, 54}, {1, 30, 65}},
             {{2, 10, 35}, {2, 20, 65}, {2, 30, 70}}
          };
sum["x", 1, Flatten[tab1, 1]]
(* 149 *)

sum["y", 10, Flatten[tab1, 1]]
(* 65 *)

sum["y", 30, Flatten[tab1, 1]]
(*135*)

etc.. The function above is just to make it easier. Otherwise, you could just do

Total[Cases[Flatten[tab1, 1], {1, _, _}][[All, 3]]]
(* 149 *)

Total[Cases[Flatten[tab1, 1], {_, 10, _}][[All, 3]]]
(*65*)

etc...

$\endgroup$

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.