2
votes

I frequently import spreadsheets into Mathematica for analysis and am having trouble coding a simple way to select non-sequential elements for the analysis. For example, If I import a spreadsheet with 20 columns and 100 rows, I commonly will need to drop selected rows/columns.

In this example I need all rows and columns 2,4,7-17. It seems logical the following code should work but results in error:

v[[ All, {2,4,7;;17} ]]

Instead I have been using:

v[[ All, {2,4,7,8,9,10,11,12,13,14,15,16,17} ]]

Is it possible to use Span (;;) to select a block of columns (7-17) while also selecting rows 2 and 4 in my example?

3
i think you mean "while also selecting columns 2 and 4" - Steve Waldman
Yes, I meant columns. Sorry for the mistake. - Nguyen Van Falk

3 Answers

1
votes

the x ;; y syntax is a special argument to Part, not a general syntax that can be used to build lists. So you could say v[[ All, 7;;17 ]], but not v[[All, {7;;17}]] -- the latter is neither a list of integers nor a special syntax recognizable by Part.

But it is pretty easy to solve your problem. You can try:

v[[All, {2,4}~Join~Table[x,{x,7,17}] ]]

for example, or

Join[v[[All, {2, 4}]], v[[All, 7 ;; 17]], 2]

Good luck!

0
votes

This is a known limitation of Part and Span. See my own closely related question:

Part and Span: is there a reason this *should* not work?

Your solution is the most common work-around. If you find it too inconvenient to build lists of indices you can try to make it easier with a custom Part function. For example:

SetAttributes[part, HoldFirst]

part[x_, parts__] := x[[##]] & @@ Flatten /@ ({parts} /. Span -> Range)

Use:

a = Range@24 ~Partition~ 4;

part[a, {1 ;; 3, 6}, {1, 3 ;; 4}]
{{1, 3, 4}, {5, 7, 8}, {9, 11, 12}, {21, 23, 24}}

This makes no attempt to handle negative index Spans which would be considerably more complicated, but perhaps it is useful at least to give you some ideas.

0
votes

another approach..

pys[{all___}] := 
 Flatten[(Switch[Head[#], Span, 
      Range @@ (# /. Span -> List), __, #]) & /@ {all}] 
list = Range[100];
list[[pys[{1, 3 ;; 12 ;; 2, 19, -3 ;; -1}] ]]

{1, 3, 5, 7, 9, 11, 19, 98, 99, 100}

This notably does not handle open ends {1,3;;} or mixed +/- spans { 5;;-5 }