1

This is a very basic question, but I searched through the official docs for list manipulation and on the site, and I wasn't able to find a specific function to delete item(s) by value from a list.

I'm currently using pattern substitution for that:

somelist := Flatten[{Range[-5,5],Range[-3,3]}]
somelist /. 0->Nothing
{-5,-4,-3,-2,-1,1,2,3,4,5,-3,-2,-1,1,2,3}

So, is pattern substitution the canonical way of deleting items by value, or will this hurt seasoned Mathematica users? What are the other solutions to delete items by value?

Sylvain Leroux
  • 1,509
  • 5
  • 15
  • 2
    DeleteCases[0]@somelist? Extension: DeleteCases[-2 | 0 | 2]@somelist. – Michael E2 Dec 09 '19 at 01:21
  • Nice @Michael! I've seen DeleteCases but I didn't understand it may be used for that. In your experience, is this more common than using /.? – Sylvain Leroux Dec 09 '19 at 01:32
  • 3
    DeleteCases is a common solution, as is its complementary function Cases. Select and Pick can be used, too, to filter a list. Nothing is relatively new to the language, so it won't appear in older code; however, it doesn't seem like a bad choice. Each approach has its virtues, and which to use might depend on the case at hand. For large packed arrays, this would be efficient for deleting 0: Pick[somelist, Unitize@somelist, 1]. – Michael E2 Dec 09 '19 at 01:57
  • 2
    Thank you very much for the explanations @Michael. This may eventually be useful for other people coming to Mathematica from another computer language. Would you consider posting that as an answer? – Sylvain Leroux Dec 09 '19 at 02:03
  • 1
    The way you remove zeros from your list is just fine. – m_goldberg Dec 09 '19 at 22:00
  • @Michael: I've synthesized your comments in an answer below. I hope you're ok with that. Feel free to edit that answer if there is something you disagree with! – Sylvain Leroux Dec 10 '19 at 00:09
  • 2
    Yes, that's fine. I've been too busy to write up an answer. – Michael E2 Dec 10 '19 at 01:07
  • Nothing unpacks arrays: Range[3] /. 1 -> Nothing // Developer`PackedArrayQ. Therefore I strongly discourage to get into the habit of using it for large numerical data. In that case, usually three-argument version of Pick is the fastest because that allows you to use a packed array as second argument (unfortunately, Boolean arrays cannot be packed). – Henrik Schumacher Dec 10 '19 at 11:57
  • 1
    Ah, I forgot this obligatory link: (3496) – Henrik Schumacher Dec 10 '19 at 13:18
  • @Henrik, I tried the three-args Pick you've suggested, but with confusing results. This works: Pick[Range[5], Range[5], Except[0]]. But this doesn't work: somelist = Flatten[{Range[-5,5],Range[-3,3]}] ; Pick[somelist, somelist, Except[0]] – Sylvain Leroux Dec 10 '19 at 13:48
  • Pick does not work with patterns. This is why it is faster. Try e.g., Pick[Range[-5,5], Unitize[Range[-5,5]], 1] – Henrik Schumacher Dec 10 '19 at 13:55
  • @Henrik, actually by digging into the possible issues section of the Pick doc, I came to that solution that does work: Pick[somelist, somelist, Except[0, _Integer]] – Sylvain Leroux Dec 10 '19 at 14:00

1 Answers1

2

To synthesize what has been said in the comments to the question:

  • Several options are available, some of them making use of relatively new features of Mathematica
  • There isn't a strong consensus to decide if some solution is better style than the other

So in no particular order:

Map to Nothing

somelist /. 0->Nothing

Suggested by myself in the question

Works well, but Nothing being a relatively new addition to the language this solution won't appear in older code

In addition, Henrik Schumacher strongly discourage to get into the habit of using this solution large numerical data. The reason is "Nothing unpacks arrays." Henrik continues by saying, for large numerical data "usually the three-argument version of Pick is the fastest because that allows you to use a packed array as the second argument (unfortunately, Boolean arrays cannot be packed)"

Using Pick

Removing matching items is actually the same thing a picking only non matching items.

However, due to the way pattern matching is implemented, using Pick with Except can lead to surprising results. Here is a working solution:

Pick[somelist, somelist, Except[0, _Integer]]

Other possible uses of Pick to remove items are:

Pick[somelist, #!= 0 & /@ somelist ]
Pick[somelist,UnequalTo[0] /@  somelist ]
Pick[somelist,EqualTo[0] /@  somelist , False]

DeleteCases

DeleteCases[0]@somelist
DeleteCases[0|1|2]@somelist

Suggested by Michael E2

DeleteCases "is a common solution, as is its complementary function Cases. Select and Pick can be used, too, to filter a list"

Cases

Based on Michael's suggestions above, I would add:

Cases[somelist, Except[0]]

Select

Select[somelist, # != 0 &]
Select[somelist, UnequalTo[0]]
Sylvain Leroux
  • 1,509
  • 5
  • 15