ListRemove() or [list] - [thisRow]

Would love to see a ListRemove() or similar to make it easier to remove an item from a list using a button. This issue has come up several times for me, where I want to do an operation like [list] - [thisRow]

Formula might be something like ListRemove([the list], [the item to remove]).

Hi @Andrew_Farnsworth :blush: !

Depending on your use case scenario but couldn’t Slice() (or Splice() maybe) help you here ? :blush:

1 Like

I assume you mean remove an item from a table?

Indeed, but I’m not sure if he just wants a more concise Splice(), or an entirely new action.

1 Like

Nope, remove an item from a list. Here’s the use case from a recent post: Toggle item in multi-select lookup field with button

maybe splice will do it?

how would splice work in this use case: Toggle item in multi-select lookup field with button

I think it will - list(...).splice(...) is how you would perform a ListRemove().

1 Like

I’ve tried that without being able to use [thisRow] as an item to remove. splice formula asks me for a number

1 Like

Okay - so… when I said:

And you said “Nope”, you really meant “Yep”?

The solution within the topic you shared already uses Splice() :innocent:

See the If() within the quote above :point_up: :blush:

I’ll admit that the whole solution within that topic seems a bit complicated to read, because of all the nested WithName() (which are there to avoid some redundancy)… but I find it elegant :blush: .

Now, in a far less elegant way but maybe easier to grasp, here’s an action button also doing what was asked in the topic you shared :blush: … Which I’m just sharing trying to answer your question :innocent:
(You’ll find the sample below :blush: )

If(thisRow.Going.Not(),
  ModifyRows(                                  //Click 1: Add the player
    Games.Filter(Date = nextGame),
    Games.RSVPs,
    ListCombine(
      Games.RSVPs.Filter(CurrentValue.IsNotBlank()),
      thisRow
      )
  ),
  ModifyRows(                                 //CLICK 2: Remove the player
    Games.Filter(Date = nextGame),
    Games.RSVPs,
    Games.Filter(Date = nextGame).First().RSVPs.WithName(CurrentList,
      Splice(
        CurrentList,
        CurrentList.Find(thisRow),
        1
      )
    )
  )
)

In the “Click 2” action (the 2nd ModifyRows()) there’s this bit of formula :

 Games.Filter(Date = nextGame).First().RSVPs.WithName(CurrentList,
      Splice(
        CurrentList,
        CurrentList.Find(thisRow),
        1
      )
    )

And what it does is:

  • It takes the table Games and look for the rows where CurrentValue.Date is equal to the nextGame (the date on the canvas).
    This actually returns a list of 1 row from the table Games. So, to effectively get the row from that list of 1 row, I’ve appended First() to the Filter().
  • Now that we have the appropriate row, we can access the values in the field RSVPs. (I.e.: the list of players)
  • As I’m going to need that list in Splice() and to avoid repeating the Filter(), I’m storing the list within the named value CurrentList using WithName()
  • All that’s left to do is to Splice() the CurrentList according to the position of thisRow (which Find() helps us retrieve) within the CurrentList
     Splice(
            CurrentList,               //Value
            CurrentList.Find(thisRow), //Start - (Where to begin to delete)
            1                          //deleteCount - How many to delete 
         )
    

Now, I’m not saying this doesn’t require a bit of work though :blush:… But I hope this helps :blush:

1 Like

I think what @Andrew_Farnsworth means is a generic way to remove an element from a list — any list really — not by the item’s index in it but by the item itself. They mentioned [thisRow] because their desired use case is to make a button in a table that would remove the row it’s clicked in from a multi-selection lookup elsewhere (e.g. remove this task from a selection of tasks in a page control). Am I right?

Indeed, a formula to List.Remove(Item) would be a nice addition to the formula language.

Meanwhile you can do this in a few other ways:

  • MyList.Filter(CurrentValue != Item)

  • MyList.Splice(MyList.Find(Item), 1)

You may prefer the former when your list is short: the formula is short and easy to understand (only keep the items that are not the one).

The latter is gonna perform better when the list is longer but this will only work if the item is guaranteed to be in the list (e.g. the button becomes disabled when List.Contains(Item) != true). Otherwise you have to safeguard it like this:

MyList.Find(Item).WithName(Index,
  If(Index > 0, MyList.Splice(Index, 1), MyList)
)

The reason: if Item is not in the list, List.Find(Item) returns -1. But this is still a valid input for the Splice() formula — it means remove the 1st item from the list end. So instead of returning the unaffected list, the formula will remove the last item in case the item you want to remove is not found:

image


By Item I mean of course anything that could be in your list — including a number, thisRow, @-reference or whatever.


P.S. List.Add(Item) would also be a welcome formula. Yes, we can ListCombine() and Splice() already. But Splice() is too technical for an average user to understand, and ListCombine() unwraps the lists it’s given, which is sometimes unwanted.

3 Likes

Splice() is indeed not the most intuitive formula to use :sweat_smile:


PS: Just in case and to clarify :innocent: : I never said I was against the suggestion :blush:. Just asked if Slice() or Splice() wouldn’t help :blush:

Thanks @Pch @Paul_Danyliuk @Bill_French for your replies. I’ve been using withname.splice, but as Paul suggested, ListRemove() and ListAdd() would be fantastic.

2 Likes

Indeed, it would. I understand now (said the very old slow guy) - you wanted to remove items from a list in the context of a table, not rows in the table (i.e., aka a List()).

That response was not intended to be snarky; just asking what he really meant because his earlier response seemed to be in conflict with his initial request.

So, in retrospect, I asked if he needed this:

… not sure if he just wants a more concise Splice()?

He responded with Nope. And then the conversation y’all responded gave him was - a more concise/less technical form of Splice()?

If my assessment is correct, I was well on the trail to understanding that he wanted a less technical round-the-barn approach.

Sometimes I’m slow, but my heart is in the hunt for answers. :wink:

5 Likes

Does this generic way work when editing reaction button response lists (on canvas and in table columns)?

Yeah, should work. A reaction value is underneath a list of People, so removing e.g. User() or a @Name Lastname should totally work.

In a table that’d be

thisRow.ModifyRows(
  thisRow.Reaction,
  thisRow.Reaction.Filter(...) // or Splice(...)
)

In a canvas that’d be Reaction.SetControlValue(Reaction.Filter(...))

Thank you Paul! I was able to get it working :slight_smile:

1 Like