I have a set of records where each record is for a particular item. An item is a member of a particular subgroup and a subgroup is a member of a particular group. One item is always a member of a single subgroup and a single subgroup can only be a member of a single group. The sample data can look like this (note that the last column of each record can be any number, in the test code below i just replace it with a random integer.
testdata = {{"Item 1", "Subgroup 1", "Group 1", 1}, {"Item 2",
"Subgroup 1", "Group 1", 1}, {"Item 3", "Subgroup 1", "Group 1",
1}, {"Item 4", "Subgroup 2", "Group 1", 1}, {"Item 5",
"Subgroup 3", "Group 1", 1}, {"Item 6", "Subgroup 3", "Group 1",
1}, {"Item 7", "Subgroup 4", "Group 2", 1}, {"Item 8",
"Subgroup 5", "Group 2", 1}, {"Item 9", "Subgroup 6", "Group 3",
1}, {"Item 10", "Subgroup 7", "Group 4", 1}, {"Item 11",
"Subgroup 7", "Group 4", 1}, {"Item 12", "Subgroup 8", "Group 4",
1}};
I would like to sort the testdata
list by the average of the group and within each group by the average of each subgroup.
I have created the code below to do that. What it does is to first gather the data by group name and then within each gathered group, gather by subgroup name. Then I generate means of each subgroup within the group and get its proper order, generate means accross the groups and get ordering and then apply that ordering using MapThread
. The code seems to work but I am not sure if it is correct, for example, i assume that GatherBy
will always generate the same order of generated groups from the same data. Moreover i guess that there might be a much more elegant and simple solution.
Any suggestions to make this better, more elegant and simpler? (Ideally easily extensible to more levels of grouping)
testdata = {{"Item 1", "Subgroup 1", "Group 1", 1}, {"Item 2",
"Subgroup 1", "Group 1", 1}, {"Item 3", "Subgroup 1", "Group 1",
1}, {"Item 4", "Subgroup 2", "Group 1", 1}, {"Item 5",
"Subgroup 3", "Group 1", 1}, {"Item 6", "Subgroup 3", "Group 1",
1}, {"Item 7", "Subgroup 4", "Group 2", 1}, {"Item 8",
"Subgroup 5", "Group 2", 1}, {"Item 9", "Subgroup 6", "Group 3",
1}, {"Item 10", "Subgroup 7", "Group 4", 1}, {"Item 11",
"Subgroup 7", "Group 4", 1}, {"Item 12", "Subgroup 8", "Group 4",
1}};
testdata[[All, -1]] = RandomInteger[5, Length@testdata[[All, -1]]]
testdatag = (GatherBy[#, #[[2]] &] & /@
GatherBy[testdata, #[[3]] &]);
subgrouporder =
Ordering /@ Map[Mean, testdatag[[All, All, All, 4]], {2}];
grouporder =
Ordering@Map[Mean[Flatten[#]] &, testdatag[[All, All, All, 4]], {1}];
MapThread[
Function[{u, v}, u[[v]]], {testdatag, subgrouporder}][[grouporder]]
Flatten[%,2]