13
$\begingroup$

I have a problem that I am working on that requires that I compare several lists of overlapping data points. As I traverse one of the lists, I'd like to only compare those data to the other lists, and not itself. So, how does one efficiently do this, especially if it must be done potentially hundreds of times? Obviously, if I can control the order in which I make the comparisons, any method would work as I can limit the number of times this has to be done. But, I can't necessarily guarantee the order.

Now both Drop and Take could be used for this, but I'm interested to know if they are the fastest methods to do this, or is there something else?

$\endgroup$

7 Answers 7

15
$\begingroup$

You can use Most[list] to do this if you want to drop last element, Rest[list] to drop the first element, and Delete[list, n] to drop the $n^\mathrm{th}$ element.

I verified that none of these unpack packed arrays, so performance should be good. Drop and Take don't unpack either, so the performance of those should be similar too, at least for packed arrays.

$\endgroup$
3
  • $\begingroup$ Ah, forgot about Delete. $\endgroup$
    – rcollyer
    Jan 18, 2012 at 17:22
  • $\begingroup$ Rest[] drops the first element, being complementary to First[]. Analogously, Most[] pairs nicely with Last[]... $\endgroup$ Jan 18, 2012 at 17:25
  • $\begingroup$ On Delete[] vs. Drop[]: Delete[Range[5], 3] and Drop[Range[5], {3}] do the same thing, of course. $\endgroup$ Jan 18, 2012 at 17:28
9
$\begingroup$

All the above are useful when you know the position of elements. Another frequent case is when you do not know the position, but know the type or value:

In[1]:= DeleteCases[Range[5], 2]    
Out[1]= {1, 3, 4, 5}

In[2]:= DeleteCases[Range[15], x_ /; 10 < x < 14]    
Out[2]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 15}

In[3]:= DeleteCases[{3, rr, "space", 3, 5, t}, "space"]
Out[3]= {3, rr, 3, 5, t}

In[4]:= DeleteCases[{W, XYZ, 3 + I 5, "wer", 1.5, 1/6}, _Complex]
Out[4]= {W, XYZ, "wer", 1.5, 1/6}

In[5]:= DeleteCases[{1, f[2, 3], 4}, f, {2}, Heads -> True]
Out[5]= {1, 2, 3, 4}
$\endgroup$
1
  • 1
    $\begingroup$ For numerical lists, the problem is that DeleteCases will unpack. So it is only efficient for unpacked lists and general symbolic expressions. If you deal with numerical lists, there are ways to efficiently extract a position of an element without unpacking (the most efficient being probably the compiled-to-C code). Then use Delete. $\endgroup$ Jan 20, 2012 at 21:19
9
$\begingroup$

Using Drop, Take, Most, etc. are fine but also consider the expresiveness of Part or [[]]

Here are some examples:

list = {3, 6, 9, 12};

In[532]:= list[[{1, 2, 3}]]

Out[532]= {3, 6, 9}

In[534]:= list[[1 ;; 3]]

Out[534]= {3, 6, 9}

In[535]:= list[[Range[Length[list] - 1]]]

Out[535]= {3, 6, 9}

In[536]:= list[[{3, 2, 1}]]

Out[536]= {9, 6, 3}

In[537]:= list[[{1, 3, 1, 1, 1}]]

Out[537]= {3, 9, 3, 3, 3}
$\endgroup$
3
  • 2
    $\begingroup$ One particularly neat thing about Part[] is that it allows for a parallel assignment construction like list[[1 ;; 3]] = list[[3 ;; 1 ;; -1]]. $\endgroup$ Jan 26, 2012 at 6:15
  • 1
    $\begingroup$ But, how do you return everything but the 9 out of your list using Part? $\endgroup$
    – rcollyer
    Jan 26, 2012 at 11:03
  • $\begingroup$ -1 Doesn't appear to answer the question. $\endgroup$ May 17, 2015 at 16:27
6
$\begingroup$

An alternative I had in mind when I wrote the question was to use Pick alongside Permutations. Pick allows you to specify a mask that can be used to select elements from a list,

In[] := Pick[(data = {a, b, c, d, e, f}), {1,1,0,0,0,1}, 1]
Out[]:= {a, b, f}

and Permuations can be used to generate such a mask,

In[] := Permutations[{0}~Join~Array[1&, Length@data - 1]]
Out[]:= {{0,1,1,1,1}, {1,0,1,1,1}, {1,1,0,1,1}, {1,1,1,0,1}, {1,1,1,1,0}}

Then,

Pick[
   (data = {a, b, c, d, e, f}), #, 1
 ]& /@ Permutations[{0}~Join~Array[1&, Length@data - 1]]

returns

{{b, c, d, e, f}, {a, c, d, e, f}, 
 {a, b, d, e, f}, {a, b, c, e, f}, 
 {a, b, c, d, f}, {a, b, c, d, e}}

Alternatively, IdentityMatrix[Length@data] could be used

Pick[data, #, 0]& /@ IdentityMatrix[Length@data]

where the pattern has been changed from 1 to 0.

$\endgroup$
3
  • $\begingroup$ is it basically just the diagonal that you want excluded @rcollyer? $\endgroup$ Jan 18, 2012 at 22:05
  • $\begingroup$ @MikeHoneychurch, pretty much. But, I expected to have to perform it a lot more often than what I've shown. In review, probably not as much as I thought. $\endgroup$
    – rcollyer
    Jan 18, 2012 at 22:36
  • $\begingroup$ rcollyer's message at 7:18 on the 18th appears to be missing a 0 in the mask: Pick[(data = {a, b, c, d, e, f}), {1,1,0,0,1}, 1] produces the message "Pick::incomp: "Expressions {a,b,c,d,e,f} and {1,1,0,0,1} have incompatible shapes"" $\endgroup$
    – Gary
    Jan 25, 2012 at 22:54
4
$\begingroup$

It is unclear whether your answer to your question represents the real problem or just an example but another way to get permutations that exclude the diagonal is to use ListCorrelate:

ListCorrelate[{0, 1, 1, 1, 1, 1}, {a, b, c, d, e, f}, 1]

{b + c + d + e + f, a + c + d + e + f, a + b + d + e + f, 
 a + b + c + e + f, a + b + c + d + f, a + b + c + d + e}

That isn't what you want obviously but my long winded explanation starts with the general form of the above:

ListCorrelate[{0, 1, 1, 1, 1, 1}, {a, b, c, d, e, f}, {1, 1}, {a, b, 
  c, d, e, f}, Times, Plus]

{b + c + d + e + f, a + c + d + e + f, a + b + d + e + f, 
 a + b + c + e + f, a + b + c + d + f, a + b + c + d + e}

So you can get an answer by using a function other than Plus in the generalized ListCorrelate:

g[x__] := DeleteCases[{x}, 0] (* or g= DeleteCases[{##}, 0] & *)

ListCorrelate[{0, 1, 1, 1, 1, 1}, {a, b, c, d, e, f}, {1, 1}, {a, b, 
  c, d, e, f}, Times, g]

{{b, c, d, e, f}, {c, d, e, f, a}, {d, e, f, a, b}, {e, f, a, b, 
  c}, {f, a, b, c, d}, {a, b, c, d, e}}

I really like ListCorrelate but unfortunately the generalized form is much slower than the default form -- you may find it up to 2 or more orders of magnitude slower depending on your problem [plea to Wolfram: make the generalized form of ListCorrelate run fast -- there is so much it could be useful for]. So the alternative in a case like this may be to revert to the default form and replace Plus in the result:

ListCorrelate[{0, 1, 1, 1, 1, 1}, {a, b, c, d, e, f}, 1] /. Plus -> List

{{b, c, d, e, f}, {a, c, d, e, f}, {a, b, d, e, f}, {a, b, c, e, 
  f}, {a, b, c, d, f}, {a, b, c, d, e}}
$\endgroup$
3
$\begingroup$

An update from v13.1 worth adding here is DeleteElements

With a list

list = RandomInteger[{-1, 11}, 13]

{8, 7, 0, 10, 3, 0, 7, 2, 3, 5, -1, 3, 3}

let's say that we want to remove the number 3 altogether, or once, or twice. We have, respectively

DeleteElements[list, {3}]

{8, 7, 0, 10, 0, 7, 2, 5, -1}

This is, of course, equivalent to DeleteCases[list, 3]

DeleteElements[list, 1 -> {3}]

{8, 7, 0, 10, 0, 7, 2, 3, 5, -1, 3, 3}

DeleteElements[list, 2 -> {3}]

{8, 7, 0, 10, 0, 7, 2, 5, -1, 3, 3}

Finally, let's say that we want to remove 3 times the 3 and 2 times the 0

DeleteElements[list, {3, 2} -> {3, 0}]

{8, 7, 10, 7, 2, 5, -1, 3}

$\endgroup$
2
$\begingroup$
list = {3, 6, 9, 12, 6};

There are, of course, many more possibilities. Some of them are:

Operator form of DeleteCases

DeleteCases[6] @ list

{3, 9, 12}

Select + FreeQ

Select[FreeQ @ 6] @ list

{3, 9, 12}

ReplaceAt

 ReplaceAt[list, 6 :> Nothing, All]

{3, 9, 12}

Query

Query[{1, 3, 4}] @ list

{3, 9, 12}

By using Alternatives we can drop 2 or more elements, for example:

DeleteCases[3 | 6] @ list

{9, 12}

$\endgroup$
3
  • $\begingroup$ Very nice. I forgot about ReplaceAt and Query completely... $\endgroup$
    – bmf
    Dec 8, 2023 at 8:32
  • 1
    $\begingroup$ I'm a close friend of DeleteElements though, because it provides a maximum of control as you showed in your answer. $\endgroup$
    – eldo
    Dec 8, 2023 at 8:39
  • $\begingroup$ Oh yes, indeed. It is very convenient! $\endgroup$
    – bmf
    Dec 8, 2023 at 8:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.