Tinderbox Forum

Building a new $List by pairing up individual values from $MyList1 and $MyList2

I’ve finally stopped procrastinating and have decided to create some challenges for myself.
My first one is as follows:

I have two lists
$MyList1: Tom;Mary;Steven;Beth
$MyList2: Brown;Johnson;Smith;White
And I want to create $MyList3: Tom Brown;Mary Johnson;Steven Smith;Beth White

I think I understand in principle what I need to do, but I’ve got no idea how to express my ideas correctly in code.

// Create two variables 
var:list vNameFirst 
var:list vNameLast 

$MyList3=; 
$MyNumber3=;

// Use .each() to loop through each list, but this is where I’m not sure what to do. 
$MyList1.each(vNameFirst); 
$MyList2.each(vNameLast)  { 
$MyList3 = $MyList1 + $MyList2 
}; 
$MyNumber3 = $MyList3.count; 

It doesn’t work, of course. And I know it’s wrong and I understand that I need to do something else. And maybe there’s an easier way to do this. And yes, I could copy and past into other software then import the list into Tinderbox, but I have a feeling that if I can understand how to complete this task, then it will help me with other challenges.

Here you go. There are a lot of ways you could do this. I’ve suggested that this be our July challenge. Would be great if others could provide their suggestions. July TBX Challenge - #2 by satikusala.

Your challenges has some assumptions, specifically the list 1 and list 2 names are in equal order/parting. One issue to consider, what happens if one of the list has more items. My solution suggestions a solution for this. Here it is:

$MyList3="";
//Determine which list is bigger so that an item is not dropped.
var:list vList;
if($MyList1.count>=$MyList2.count){vList=$MyList1}else{vList=$MyList2};
$MyList=vList;
//Generate MyList 3. vPlace needs to start at 0 because Loop.at() is numbered from 0. In other words it considers the first item in a list as starting at point 0 therefore we want vPlace to be 0 for the first iteration of the loop. 
var:number vPlace=0;
vList.each(x){
  $MyList3+=$MyList1.at(vPlace)+" "+$MyList2.at(vPlace);
  vPlace+=1;
};

TBX L - Combine Lists of First and Last Names.tbx (81.6 KB)

@eastgate or @mwra is there a way to feed the .each operator, or is there some other operation that we can use, a counter a number to the loop operator and tell Tinderbox how many times we want to cycle through a loop? If this was possible, you could do a max calculation on the lists e.g. max(list($MyList1,$MyList2) and then take the bigger number and feed it into the loop. I’m not sure how this would be done.

I would love it if someone else can take up this challenge and suggest a different approach.

The (relatively new) range operator 1…5 is what you chiefly need. Get the length of the lists, and try $Fullname=""; 1..count.each(n){$FullName[n]=$FirstName[n]+$LastName[n];}

1 Like

.@mwra and I talked this morning. The function i was looking for was …(range). It lets you integrate a loop a number of time.

Here is what the code would look like with range:

$MyList3="";
//Determine which list is bigger so that an item is not dropped.
var:list vList;
if($MyList1.count>=$MyList2.count){vList=$MyList1}else{vList=$MyList2};
$MyList=vList;
//Generate MyList 3. vPlace needs to start at 0 because Loop.at() is numbered from 0. In other words it considers the first item in a list as starting at point 0 therefore we want vPlace to be 0 for the first iteration of the loop. 
var:number vPlace=0;
0...(max(list($MyList1.count,$MyList2.count))-1).each(x){
  $MyList3+=$MyList1.at(x)+" "+$MyList2.at(x);
  vPlace+=1;
};

Note, this challenge is a bit confusing due to its untested assumptions. It assumes:

  1. The two lists are of the same length, if they are not the code should not run and warn the operator because the source data is incorrect and needs fixing.
  2. The two lists are sorted in the same order., i.e. item 1 in list one is paired to be paired with item 1 in list 2, etc. The code can’t test this. This is down for the user to check that this is correct.

Thanks is this supposed to be 1...$List.count.each (n)? We (me and @mwra) are asking because we thought the range operator are three dots and what is count counting? We presumed that you’re actually counting one of the lists (assuming both soruce lists are the same length).

The other interesting insight here is that n in the loop is the current number in the range. Is this correct? IOW, in interaction 2 of the loop the value n is therefore 2.

I’ve answered my own question in the last paragraph of the post above…

I’ve updated my article on the range (…) operator, to fix some earlier typos and to explain how the operator works with the loop variable is the .each() operator. As I explain there:

The range operator can be useful for performing a task a specific number of times using the List.each() operator:

1...10.each(x){var vPath="/container/item "+x; create(vPath);}

and in that example the value of the loop variable x value is the value for the source list generated by the range operator, i.e. it is the same as would occur in this literal example:

"1;2;3;4;5;6;7;8;9;10".each(x){var vPath="/container/item "+x; create(vPath);}

In both cases, on the second iteration of the .each() loop, the loop variable x would have the value 2.

I’ve also added a cross-reference in the article on List.each().

I’ve further updated the range article to reflect using expressions like $MyList.size to define or or both ends of the range. As described in the article it may be necessary to add extra parentheses.

So:

Thus, if $MySet has 4 items:
$MyList = 1 ... $MySet.size; gives “1” WRONG
so add parentheses around the expression:
$MyList = 1 ... ($MySet.size); gives “1;2;3;4” CORRECT
If chaining operators to range specified using expressions, consider using parentheses around the whole range definition:
(1 … ($MySet.size)).each(x){$Text+= x+"\n";};`
The last example actually works without the parentheses but illustrates the concept.

I think that’s helped flesh out a few edge cases for use of the range operator.

Thank you for the code and the comments @satikusala, @eastgate, and @mwra
I’ve learnt a lot.
I approached this by trying to focus on just the immediate problem at hand and once I found myself repeating the same unsuccessful steps a few times, I knew it was time for my very first post to the Forum.

2 Likes