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

Thanks @boston85719 - that’s really helpful. I have a list of uniques in the way you mentioned.

The only thing is, you can’t group by those. So at the moment each cell of the RG is looking up the occurrences of the word in the list of companies’ specialities fields and counting.

The one thing I’ve not cracked is ordering a group by the calculated field… will do some looking now.

image

See that SORT action that List Shifter has?

Hey @killianAB. Yeah, you can do this with List Shifter. As you’ve noticed, when you modify a Bubble list with “:plus item”, you’re appending the new value at the end of the Bubble list.

If you would instead like to take some list and prepend a value to the beginning of that list, you can do this in List Shifter in many different ways, but probably the best way is using the PROCESS List action. The PROCESS List action and the Processed List output are for situations like this where you desire to construct some entirely new list in a specific way.

The most straightforward way to do this in List Shifter is to use the Array x.concat(y) operator in PROCESS List. This takes two arrays and joins them together with the items in Array X, followed by the items in Array Y. (It’s literally just performing the JavaScript .concat() operation.)

As an example, if I have a list like [1, 2] and another list like [3, 4, 5] I can combine them into a new array [1, 2, 3, 4, 5] with this operator and then publish that new list to List Shifter’s Processed List output.

We can use this feature to take our single item (by first turning it into a list of just that item) and concatenating it with some existing list. Of course, this is simplest if we use a List Shifter’s Processed List output as the place we construct our list all the time. (Which may be what you want to do.) But we can also just take that list and use it somewhere else (like feed it into the List Shifter you’re using to do SWAP items or whatever).

Have a look at this simple example in run mode first:

When you click “Add Item” on any product in the left repeating group, it gets concatenated with the existing list and appears at the top of the list (which I’ve displayed both as a text list of product names and also in a Repeating Group).

The setup for this is pretty simple. If you look at that project in edit mode you’ll see on the “Add Item” button, there’s a workflow with a PROCESS List action set up as follows:

That’s pretty much it, just one step, and instead of iterating over some list, we just “Do Once”.

As you can see our operator in step 1 is Array x.concat(y). So this takes the value in “LS Type List Constant” (which we will set up to be the single item we want to add, converted to a list) and then concatenates the contents of the Processed List on to that.

Then, we need to take this result (which is a new list) and push it to one of List Shifter’s outputs. In this case, the natural thing to do is make the new value of our Processed List this value. We do that by setting “Set Proc List to RS1” to yes as shown here:

A couple more things to note. We supply the item we want to add to the list via the “LS Type List Constant” input. In case this name doesn’t mean anything to you, it means, “a list of List Shifter’s (Process Output) Type”. I’ve set my List Shifter element’s Process Output type to be “Product” (you have to set the Process Output type to use the PROCESS List action).

Scroll WAAAAYYY down the Process List dialog to see the input for the LS Type List Constant field. Here, we set this value to be the Current Cell’s Product (but this could be any product) and then I turn that single value into a list with just that one item using the :converted to list operator:

The other thing I’ve done is set the “Don’t Clear Processed List” option to yes, so that it’s preserved. (By default, List Shifter will clear the Processed List before executing, but we don’t want that in this case, obviously.)

Hi Keith, is the backend part of the plugin ready?

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.