1

Hi (and sorry for ambiguous question Title, welcome to better ones)

I currently have a table of data looking like this:

CLASS       Type A  Type B  Type C
A              1       3      7
B              2       4      8
C                               
D               

Either through formulas (I don't see how) or a script, I am trying to get the combination of each 'Class' with each type, for example:

A1, A2, A3, A4, A7, A7 and A13 A14 A17 etc and A137 A138 etc (+ all other possibilities). So far I only managed to get the '2 digits' version.

Code so far below (in my data I have some extra columns which tell me what types I need for that specific class):

function expand(){
  //create the sheet to use
  var ss = SpreadsheetApp.getActive().getSheetByName('data');
  //create blank array
  var fin_resultAry = [];
  //extract the range of data
  var main_Range =  ss.getRange('A2:D5').getValues();
  //extract all the variations of data
  var range1 = ss.getRange('E2:E3').getValues();
  var range2 = ss.getRange('F2:F3').getValues();
  var range3 = ss.getRange('G2:G3').getValues();
  
  //create dictionary with variations
  var var_dict = {1: range1, 2: range2, 3: range3}
    
  //main for loop
  for(var k = 0; k<main_Range.length;k++){
    //push the initial no type variation
    fin_resultAry.push(main_Range[k][0]);    
    //create the loop to check what class variations have the set value == true
    for(var i = 1; i<=main_Range[k].length;i++){
      if (main_Range[k][i] == true){
        //for each of the variations add the var string to the initial class and push it
        for(var j = 0; j<var_dict[i].length;j++){
          fin_resultAry.push(main_Range[k][0] + " " + var_dict[i][j][0]);
        }  
      }
    }
  }    
  return fin_resultAry;
  }

Also note that my data has a lot of 'Classes' and more than 3 types which makes using formulas impossible as they are limited to X number of rows/characters/etc.

TheMaster
  • 45,448
  • 6
  • 62
  • 85
Dnib
  • 13
  • 1
  • 6
  • 1
    I've answered a couple of similar questions using formulas and you are right, they are limited by the size of the sheet/size of cell. The approach should be the same though, for the types with 2 choices in each column you would basically have to count in base 3, e.g. the number 012 would mean ' don't include type A, take first choice from type B (3) and second choice from type C (8) then put it with class to get (say) A38' – Tom Sharpe Jul 15 '18 at 18:26
  • 1
    I read the question as only wanting 1 number from each column so I got 3^3-1 = 26 - perhaps OP can clarify. – Tom Sharpe Jul 15 '18 at 19:35
  • Yes, only one of each column (i.e. A12 is not a valid combination for my purposes in the example above). – Dnib Jul 15 '18 at 19:42

2 Answers2

1

Here is an implementation of the "counting in base 3" method for generating the different combinations:

function expand(classes,types) {
 //No. of classes
  var nClasses=classes.length;
  //No. of types;
  var nTypes=types[0].length;
  //No. of 'subtypes' i.e. rows in type columns;
  var nSubTypes=types.length;
  //No. of combinations to go through for types;
  var nCombinations=Math.pow(nSubTypes+1,nTypes)-1;

  var resultArray=[];
  var iRow;
  var comb;
  // Loop over classes
  for (var iClass=0;iClass<nClasses;iClass++)
  {
    var class=classes[iClass];
    // Loop over all combinations of types
    for (var iComb=0;iComb<nCombinations;iComb++)
    {
      var shift=iComb;
      comb=class;
      //Pick out array elements for one combination of types
      for (var iType=0;iType<nTypes;iType++)
      {
        iRow=shift%(nSubTypes+1);

        if (iRow<nSubTypes)
          comb=comb+types[iRow][iType];

        shift=Math.floor(shift/(nSubTypes+1))
      }
    resultArray.push(comb);
    }
  }
  return resultArray.sort();
}

It's called as

=expand(classes,types)

e.g. for the test data

=expand(A2:A5,E2:G3)

enter image description here

Tom Sharpe
  • 30,727
  • 5
  • 24
  • 37
  • Thanks! It will be a bit of a challenge to adapt it to take into consideration true/false, however hopefully I'll manage! I've tagged this as the correct solution! thanks again – Dnib Jul 17 '18 at 20:30
0

=ARRAYFORMULA(SORT(A2&(SUBSTITUTE(TRANSPOSE(QUERY(TRANSPOSE(IF(SPLIT(REGEXREPLACE(DEC2BIN(ROW(A1:INDEX(A:A,SUMPRODUCT(COMBIN(COUNTA(B2:D3),ROW(INDIRECT("A1:A"&COUNTA(B2:D3))))))),COUNTA(B2:D3)),"\B","☢"),"☢"),SPLIT(TEXTJOIN("",1,B2:D3),""),)),,2^99))," ",))))

  • COMBIN(n,k) to get Total number of Combinations for given array B2:D3 [COMBIN(6,{1..6})=63]
  • DEC2BIN¹ to get actual each combination in 1-0s. [000001,000010..]
  • SPLIT each number [{0,0,0,0,0,1};{0,0,0,0,1,0}..]
  • Use IF to change 1,0s to corresponding number array created by SPLIT/TEXTJOIN [4,8,48..]
  • QUERY to concatenate and SUBSTITUTE to remove spaces and SORT

FILTERed Version for Type A and C:

=ARRAYFORMULA(SORT(A2&(SUBSTITUTE(TRANSPOSE(QUERY(TRANSPOSE(IF(SPLIT(REGEXREPLACE(DEC2BIN(ROW(A1:INDEX(A:A,SUMPRODUCT(COMBIN(COUNTA(FILTER(B2:D3,REGEXMATCH($B1:$D$1,"A|C"))),ROW(INDIRECT("A1:A"&COUNTA(FILTER(B2:D3,REGEXMATCH($B1:$D$1,"A|C"))))))))),COUNTA(FILTER(B2:D3,REGEXMATCH($B1:$D$1,"A|C")))),"\B","☢"),"☢"),SPLIT(TEXTJOIN("",1,FILTER(B2:D3,REGEXMATCH($B1:$D$1,"A|C"))),""),)),,2^99))," ",))))

Related Questions:
¹ https://stackoverflow.com/a/46360890
² https://stackoverflow.com/a/47932221
³ https://stackoverflow.com/a/50067998

The table in the question is assumed to be in A1:D5

TheMaster
  • 45,448
  • 6
  • 62
  • 85
  • Thanks, however as mentioned, this will not work because of the actual size of my data. The answer needs to be a script. – Dnib Jul 15 '18 at 18:44
  • 'Class' has approx 400 rows and I have 10 type columns, each with 2-13 sub-rows. I had already found a stack overflow thread with someone suggesting a formula which would normally work and was giving me a size error. + the fact that I have an intermediate check to do (I only count certain type for each class if a separate column is 'True') – Dnib Jul 15 '18 at 18:50
  • 'Error The resulting array was too large.' After actually trying it even with 2 Type columns :) – Dnib Jul 15 '18 at 18:55
  • In this case I think sheets can handle it, but only because I am not using all classes. As mentioned I have some true/false columns validating which type can be added for each class. For example my 'first order' (each class and each type once) script only produces 7.700 rows. – Dnib Jul 15 '18 at 19:14
  • Thanks for the support! I'm honestly not certain myself whether it's plausible, but I gotta give it a try in this case :) – Dnib Jul 15 '18 at 19:23