Automatically generate all possible combinations from attributes?

Suppose you have a prototype with an Attribute which can have values A or B, and another Attribute with values possible of either X or Y.

Can Tinderbox be made to automatically generate a note with each possible combination of attributes (AX, AY, BX, and BY)?

Sure.

I’m not sure why it matters, though, that the note in question is a prototype. Which suggests that I don’t actually understand the task!

Ah. How would one do that?

Well I was thinking prototype because then if one changed the prototype attributes all its potentially many, many children would be automatically changed.

Ok, making notes we can use create(). So, if we have a list of the (paths of) notes needed, we can iterate the list and call create(0 for each item.

So, the real question is how do we get that list? First, some assumptions

  • the aim is to make a number of new notes based on the unique pairings of the current values of $Attribute1 and $Attribute2
  • We want to make a Set as we don’t want duplicate names.
  • $Attribute1 & $Attribute2 can have some overlapping values (i.e. we’ll allow for this. IOW, if both have value ‘A’ we don’t need a note ‘AA’ (or do we we? You’ve not specified).
  • We only need note per value combo. We don’t need ‘AX’ and ‘XA’ as either note stands proxy for both
  • You don’t say how the two values are merged, so let’s assume a space character. We don’t know what the real values are and simply concatenating (joining) the raw values might generate hard-to-read note titles.
  • You don’t say where the new notes go, so we’ll assume a root level container ‘Values’ (i.e. a Path /Values)
var:set vSet1 = values("Attribute1"); // i.e. "A;B;C"
var:set vSet2 = values("Attribute2"); // i.e. "X;Y;Z"
$MySet =;  // reset as empty
vSet1.each(anItem1){
   vSet2.each(anItem2){
      if(anItem1!=anItem12){
         $MySet += (anItem1+" "+anItem2);
      }
   }
}

Then we can check we have the right number/form of new note titles. Now to make the notes:

// store container for new pre-value notes
var:string vContainer = "/Values";
$MySet.each(aTitle){
   create(vContainer,aTitle);
}
$MySet=; // reset MyList

Now you know it works, you can do it all in one task and without needing to use any attributes:

var:set vValues1 = values("Attribute1"); // i.e. "A;B;C"
var:set vValues2 = values("Attribute2"); // i.e. "X;Y;Z"
var:set vTitles; // starts as empty Set 
vValues1.each(anItem1){
   vValues2.each(anItem2){
      if(anItem1!=anItem12){
         vTitles += (anItem1+" "+anItem2);
      }
   }
}
// store container for new pre-value notes
var:string vContainer = "/Values";
vTitles.each(aTitle){
   create(vContainer,aTitle);
}

You can apply that code (e.g via a stamp) to any note as it doesn’t care where it is run.

Here’s my test doc: make-value-notes.tbx (125.6 KB)

Read the assumptions note, then select any note and try out the stamps in the TBX. To ‘reset’ the file, simply delete the container ‘/Values’ if it is created. N.B. ‘note4’ tests the assumption about shred values, as without the extra logic (see above), a note ‘AA’ would be produced.

If looking to parameterise the solution, note that Tinderbox (as at v9.5.1) cannot use a variable as the argument for values(). So:

$MyList = values("MyString"); // gets unique values for attribute 'MyString'
$MyList = values($MyString); // gets unique values for attribute name stored in $MyString
//but
var:string vName = "MyString";
$MyList = values(vName); //  FAIL - DO NOT USE

If you needed both ‘A X’ and ‘X A’ cases, then add an extra loop with vValues2 on the outside and the vValues1 as the inside. the existing code will still avoid, ‘AA’ , ‘BB’.

You don’t have to create a Set, and may chose not to as it re-sorts values in A-Z lexical order. But, if you do, you need to think about using List.unique` to avoid duplicate-named new notes.

Doing this for more than two source lists is more complex and might scale badly … but is likely possible.

3 Likes

Wow, thank you for this wonderful level of detail! Much appreciated.

1 Like