Forum Academy Marketplace Showcase Pricing Features

List Shifter: Reverse, Rotate, Swap and ITERATE (Loop) Over Bubble Lists | Now at v1.4: Adds Numeric Option, GET INDEX Action

Wouah ! The explanation is so clear
Thank you so much

Hey @rob6, see my responses in this thread, with links to examples of doing this type of counting and sorting. The not possible sort repeating group by

Hello everyone,
I’m using ListShifter to iterate a list of things returned by a plugin, and add them 1 by 1 to the database. Technically, it works, but it only returns the 2 first elements of the list, even though there’s 20 items in it… Here’s my setup, any ideas of what I’m doing wrong ? Thanks in advance for your help !

: the list

: the set-up

: the results

Hey @monicabayama : It’s possible that you have some conditions (“Only when”'s) on your workflow or action that are causing this. However, it’s more likely that you’re simply being impatient.

Note that Create/Make Changes to a Thing actions take time to complete. More time than you might think. I feel like I made a video about that but can’t find it now. Just know that you can use List Shifter’s iterate feature with Create/Make Changes actions in the iterative workflow and think that the objects have been created, but they actually have not been.

(They’ve been created in your local cache, but the backend has not caught up with you yet. I swear I have a video demonstrating this, but again I can’t find it right now. Maybe a stan will point to that? None of this is documented, BTW, because Bubble does not expect you to be attempting to do such things.

Let it suffice to say that on page Create actions take but a moment, but there’s actually a more complicated – and slow – process going on. If you attempt to leave the page and Bubble throws a warning that it’s not yet done with saving changes, well, believe what Bubble tells you.)

I see, thanks for the answer !

In my case, I think that it was because I was using the step by step debugger option in the preview mode, when I ran it in live mode, it worked.

Hi all,

Trying to use this awesome plugin to solve this seemingly easy issue, but no go. The problem is that I can’t pass the Processed List to a :GroupBy to be used in the chart. Was also thinking that I’ve generate a list of dates, concerted to string and left-trimmed up until the hour of the day. Any other ideas?..

I’m trying to generate a chart of a table’s create activity within a day, grouped by hour. I’ve spent hours on it and couldn’t figure out a way to get it done (including trying to use List Shifter/Toolbox plugin’s List Item Expression to build a list of the create dates but always normalized to 00 minutes, and then use that for the chart using a :Groupby).

TIA!

Are you creating anything in the Processed List? Processed List isn’t something that just exists, you can only put values into the Processed List via the PROCESS List action.

Are you sure you’re not looking for Original List or Shifted List?

LMK!

Hey @keith thanks much for the quick reply. Yeah, I’ve been able to get as far as creating a Processed List, type text, with a text version of the date. And I can then display that in an RG with the text field trimmed to a certain number of chars, but that’s of limited use. I tried the various options in the plugin but didn’t see a “text left(y)” type operation. And wasn’t sure how to use the “eval(x)” option. So I’m stuck. Perhaps I’m headed down the wrong path and there’s a simpler way of doing this? Essentially, I need a way of extracting a list of date/hours with a count for each of those. TIA!

Vanilla Bubble has all of the date formatting features that you would need. If you have a list of dates, you can convert them to any useful presentation using :formatted as (and set up your Custom formatting).

Perhaps I don’t quite understand the issue you’re running into @akalati, but instead of (for example) attempting to trim your text representations of the dates in PROCESS List, ensure the dates are formatted correctly in the expression you use to send them to List Shifter.

Then, you can use PROCESS List to count each unique item in the list. You would do this by passing PROCESS List the list of unique values as the List to Iterate Over, and then do a step like so:

(Where I’ve put the yellow highlight, you would use an expression like This ListShifter’s Original List :unique items to Bubble-ize the list, removing the duplicates.)

What you’d end up with is a list of numbers (exposed at the Processed List output) counting how many of each unique item are found in the full list.

Thanks much will give it a try!

1 Like

:clap::clap::clap: can’t put enough clap emojis in a single message to express my gratitude

thank you so much @keith !!

Hi Keith,

Awesome plugin. Definitely sending you a cup of coffee!

I have a very simple workflow but can’t seem to get it to work correctly with List Shifter.

  1. When Lister Shiter 1 is updated Process LS1 & LS2. Results are two lists of numbers. Works fine.

What I want to do next is take each item in LS2 Processed List and Divided by each item in LS1 Process list. eg. LS2 Process List item 1 / LS1 Process List Item 1… and so forth.
I can’t seem to get this to work.

What I’ve done:
2) LS3 list to shift is LS2 processed list.
3) when LS3 is updated Process LS3 - Operant X is (All Values - Processed List of LS2). Operator is divide. Y is LS 1 Process List #item number This LS current Iteration Index ( because this expects a single value)

That doesn’t work. Am I on the right path here?

thanks

Hey @hello.plannwin, thanks for the kind comments. So, I’m not sure exactly what it is you ultimately want to do (because you don’t say), but as for the case of dividing one list of numbers by another list of numbers, you can do this.

However, note that the natural outcome of taking List 1 and dividing each element by every element in List 2, would be an array of arrays (as Bubble would have it, a List of Lists), and Bubble does not have a simple data type that supports this. (Well, we could create a Thing that has an array of arrays on it, but this cannot exist in the page and so is not helpful to us here.)

Example: If list 1 has 10 values in it and list 2 has 10 values in it and we do an array-wise division like you’re trying to do you’d end up with a 10 x 10 array of 100 values, right?

We can’t export a 2-dimensional array like this to Bubble, but we can flatten it into a one-dimensional array. More to the point, we can build the answer that way. (We just need to understand that our vector of 100 represents 10 chunks of 10 divisions, yeah?)

All we can return to Bubble from List Shifter is a one-dimensional array of simple data types. Lists are one-dimensional arrays. For example, the numbers one through ten: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. This would be a List of type number in Bubble parlance.

OK, so how do we do your operation in List Shifter. Here’s an example page where I have 2 List Shifters, each holding a list of numbers. For clarity, I use a third List Shifter to do the division computation using PROCESS List. But note that we could have done this without needing a third List Shifter.

That third List Shifter (blue one) just takes the second List Shifter’s list as its “list to shift”.

The PROCESS List step is set up like this:

We’ll iterate over its list (which is the numbers from LS 2). So we import the values from LS 1 using the LS Type List Constant (way down in the dialog). I’ve activated DEBUG mode so, in our console, we can see what’s happening:

And then back to the top, here are our steps: In step 1 we do the listwise division. As I think you know, if one of our operands is a List, we’ll actually do the operation on all of the elements in that list, yielding us an array. So, if you open your console and click the DIVIDE button, you’ll see, for the first iteration, we get the values for LS 1 array divided by the first value in LS 2:

Now, what do we do with the result of Step 1 (RS1)?

Instead of pushing this to Processed Result, we’ll instead use the Custom List. Custom List is an internal value that’s a little like Processed List, but it is only published when we say so.

And what we’re going to do in Step 2 is take the Custom List (which will start out as an empty array) and CONCATENATE RS1 (the result of step 1) on to it. Like this:


This says, whatever Custom List is right now, take the array from RS1 and append it. So in the first run through, Custom List is [] and RS1 is [0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5]and we get [0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5] as the result of step 2 (RS2).

And then, in this second step, we SET the value of Custom List to be this result (see circled “yes”).

There are no more steps (but a little more setup) that I’ll discuss below. Now on our second iteration, what will happen is that the values in LS 1 will be divided by the second value in LS 2, and in my example this yields [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5]:

Then the second step concatenates that result onto Custom List (which already has 10 numbers in it), and now it’s the first 20 results.

This continues until we have walked through all of the values in LS 2. Here’s what we have in our final result (an array of 100 values):

NOW, as I mentioned, Custom List is only published when we say so, so down at the bottom of PROCESS List dialog, I set Publish Custom List (which happens at the very end of the iteration cycle):

And now my answer appears at LS Compute’s Custom List output.

Additionally Custom List is persistent and executing PROCESS List does not automatically clear Custom List. So, in this case, we would want to ensure Custom List is clear before we do PROCESS List and we can do that with the SET Custom List action:


We do that by setting Custom List to empty and, by also setting Publish Custom List to yes, we also clear the values present at the Custom List output.

Inspect the edit mode for the example page to see all of this in place.

I just pushed minor update 1.9.24 to List Shifter, which fixes an obnoxious bug that would throw an error if you tried to SET Custom List to empty, but the Custom List was already empty.

(@boston85719 you had reported this and it’s now fixed - sorry for the delay with that)

1 Like

Hi Keith,

Thank you for the time you took for a comprehensive response. But I think I may have confused you. Sorry. What I want to achieve is fairly simple. I just want to do math on each item in two lists.

For example:

List 1: 1,2,3,4,5,6,7,8,9,10
List 2: 10,11,12,13,14,15,16,17,18,19,20

Take LS1: Item1 / LS2: Item1 = 1/10
Take LS1: Item 2/ LS2:Item2 = 2/11
And so forth until the end of the list. I thought the current iteration index number would give me the current item number of the list, so should be able to get LS2:Item#current iteration index number for the Y operand? but it doesn’t.

While I have your attention. How does LS handle uneven lists?

for example:

LS 1: 1,2,3,…,100
LS2: 70,71,…100
Sum two list together:

Result: 1,2,3,…140 (70+70), 142 (71+71), …,200

Thank again.

@hello.plannwin:

Just to be clear (I think you’re using PROCESS List) but if not: Don’t use Iterate to do simple math. Use PROCESS List. I’ve updated the example for your (much simpler) use case of dividing each number in some list by the corresponding number in another list.

How this PROCESS List action is set up is as follows. In this case I’m using LS 1 as the List Shifter we compute in. As in the previous example (which is still found in the page), we’re going to import the second list of numbers via the LS Type List Constant:

We have to do this because there is no other way of referencing the individual items in LS 2 from within PROCESS List. Unlike Iterate (which is slow and clunky for simple operations like this), we are not iteratively firing off a Bubble workflow. We are instead running an entire native JavaScript function and then returning the results of that function back to Bubble.

Back up in our workflow steps, our number from LS 1 is just “List Item” and its corresponding item in LS 2 can be referenced as LS Type List Constant ITEM (<-- this literally means “the corresponding item in LS Type List Constant” – handy, eh?).

So this could be set up as a one-step operation. That step would be:


:point_up: you can’t quite see it but Operand Y is “LS Type List Constant ITEM”.

It sounds like what you were trying to do is use the expression input for Step Operand Y. That’s of no use to us here. Expression fields are only evaluated right before an Action is run. PROCESS List cannot communicate back up to Bubble what iteration step we are on. So there’s no expression you can write that will ever return to you the number you want. (You can get, for example, ONE value from LS 2, like writing LS 2's Original List:item #4, but that’s going to be constant.)

Now, you had asked about lists of different sizes and how they are handled. It’s because of this that I said above that we could make this a one-step operation, but it’ll only work properly if LS1 and LS2 are the same length.

What if, as in my updated example, LS1 and LS2 are different lengths? (Here, LS1 is longer than LS2.) There are a couple of things to know:

  1. Most of the time in PROCESS List, if some result is non-sensical or doesn’t exist, the value returns as null. (Null is a special JavaScript object, that’s basically the same thing as Bubble’s “is empty” concept.) And this is what happens if we refer to LS Type Constant ITEM, but there is no value at that location (e.g., when we are on iteration 8 of our process, but the list we take from LS2 is only 7 numbers long).

  2. For some math operations, this is not a big deal and is more-or-less what we would want/expect. For example, a number + null is like number + 0, it’s just number. Same thing with minus. And similar with * (multiply). But division is a special case and, in JavaScript there’s no divide by zero error (and divide by null is the same as divide by zero) and yields the special numeric value Infinity. Even though this is a legal value, Bubble doesn’t like it if we try to push our list back to Bubble, so you need to handle that.

It’s up to you how you handle it, but here’s what I did. So, continuing on, I added two more steps to the PROCESS List action that would otherwise be done:

First, we don’t just push RS1 to the processed list. We do a step 2 like this:


We take RS1 and ask if it’s finite or not. If the number is finite (it’s not the special value Infinity), this step (RS2) will be true. If RS1 is Infinity, the value of RS2 will be false.

Now in step 3, for our value we just take RS1 (this returns the value of RS1 and stores it in RS3). And then we say, “push this value to the Processed List”… but “only if RS2 is true”. We do that like so:

And now what happens is that values are only pushed to the Processed List if they are regular old numbers and not Infinity. So our resulting output will have just the first 7 divisions, not the 3 “bogus” divisions.

There are many other ways we might accomplish this in PROCESS List, but I’ve gone on long enough.

*** BTW, when building this I discovered there way a stupid typo in PROCESS List’s implementation of isFinite(), so I fixed that. Update your List Shifter plugin to the latest version.

I mentioned this in the preceding reply, but I pushed a lil’ bugfix update to List Shifter as version 1.9.25. This fixes a derpy bug in PROCESS List’s isFinite() operator. It simply didn’t work and would throw an error. Now it works as expected.

(Clearly nobody uses that operator as I hadn’t received any reports of an issue there. Go figure. But if you’d like to know how this operator is useful, see the preceding reply from me.)

Hey @keith! Big fan of this plugin! Couple pots of coffee coming you way soon! :slight_smile:
I had a quick, but non-trivial question: Is it possible to have embedded iterations?

If it helps, here’s the situation: I have an RG of type A (from a ListShifter list), each cell of which has an RG of type B (also from a Listshifter list), where each B has multiple options. I want to let the user pick one option for each B and then be able to save their choices for the associated A. I was hoping I could do this by simply iterating over the A’s and then having an embedded iteration over the B’s in each step, but I don’t seem to have the option to start an iteration over the list of B’s.

(I know I can do this with something that amounts to a ‘save’ button in each cell of the A-list, but I’d rather let the user save everything at once.)

Sorry if that wasn’t coherent. I’ve been working on this for a few days and I think I’m starting to suffer from the Tetris effect…

Thanks, Keith,
works great

Hello @keith,

I´m doing my best trying to learn how your plugin works man but I don´t even know where to star of if it´s possible.

So I want to let my users duplicate an invoice with its invoice lines (invoice is a data type and invoice lines is another data type connected to invoice) several times, incrementing the date of the invoice next to the previous one by one or two months, depending on an input field.

I´ve tried to do this via API workflows but the server maxes out and I was wondering if this would be possible with your plugin.

Hopefully it´s possible and if you can just point me where to start I would really appreciate it.

Thanks a lot and have a good day.