6
$\begingroup$

I have a list as follows:

lis1={{{a1,b1,c1,d1,e1},{a2,b2,c2,d2,e2}},
{{a3,b3,c3,d3,e3},{a4,b4,c4,d4,e4}}}

and would like to delete certain elements from it resp. pick certain elements to get a list as follows

lis2= {{{a1,c1,e1},{a2,c2,e2}},
    {{a3,c3,e3},{a4,c4,e4}}}

My problem is that the data I would like to select are not in an consecutive order (otherwise I could use the Part function). Does anyone have an hint?

$\endgroup$

7 Answers 7

7
$\begingroup$

You actually can still use the Part function!

If you know the positions explicitly you can try:

lis1[[All, All, {1, 3, 5}]]

Or, if they follow a regular pattern:

lis1[[All, All, 1 ;; 5 ;; 2]]
$\endgroup$
9
$\begingroup$

Just learned from this answer by ciao that Downsample is made for this kind of task:

Downsample[#, {1, 2}] & /@ lis1
(* {{{a1, c1, e1}, {a2, c2, e2}}, {{a3, c3, e3}, {a4, c4, e4}}} *)

You can also use Take, Drop and Extract to get the same result:

Take[#, All, {1, -1, 2}] & /@ lis1
Drop[#, {}, {2, -1, 2}] & /@ lis1
First@Rest@Extract[lis1, {{0}, {;; , ;; , ;; ;; 2}}]

You can use arbitrary lists for Part specifications with Part and Extract. For example

#[[All, ;; , {1, 4, 5}]] &@lis1  (* or *)
First@Rest@Extract[lis1, {{0}, {All, ;; , {1, 4, 5}}}]

both give all rows and columns 1, 4 and 5 in all matrices in lis1:

(* {{{a1, d1, e1}, {a2, d2, e2}}, {{a3, d3, e3}, {a4, d4, e4}}} *)
$\endgroup$
5
  • $\begingroup$ That only works for the specific example. OP said: "My problem is that the data I would like to select are not in an consecutive order (otherwise I could use the Part function)." $\endgroup$
    – rm -rf
    Commented May 2, 2015 at 17:57
  • $\begingroup$ @TheToad, i may be wrong, but i thought the quote meant the OP was not aware of the part specifications other than from;;to (since Part specs can be any list). $\endgroup$
    – kglr
    Commented May 2, 2015 at 18:08
  • $\begingroup$ @TheToad Even though the origins of the name change are clear, it will take (me) some time to get used to. Is it planned as permanent? $\endgroup$ Commented May 2, 2015 at 19:34
  • 1
    $\begingroup$ @LeonidShifrin It was just for fun, mostly. I came across an image that I really liked and just went along with it :) How long I'll keep it, I don't know, lol. I've always treated online personas as ephemeral and have fun changing things around but I can see how it might be confusing for others, especially when there are some artifacts and other bread crumbs lying around :) I can revert if you'd like me to/find it confusing. $\endgroup$
    – rm -rf
    Commented May 4, 2015 at 4:34
  • $\begingroup$ @TheToad Oh no, by all means keep it as long as you want :). It's fun to everyone. I wasn't really serious. $\endgroup$ Commented May 4, 2015 at 9:00
6
$\begingroup$
lis1 /. b1|d1|b2|d2|b3|d3|b4|d4->Sequence[]
$\endgroup$
2
$\begingroup$
lis1 = {{{a1, b1, c1, d1, e1}, {a2, b2, c2, d2, e2}}, {{a3, b3, c3, 
    d3, e3}, {a4, b4, c4, d4, e4}}};

MapAt[Nothing, {All, All, {2, 4}}] @ lis1

ReplaceAt[_ :> Nothing, {All, All, {2, 4}}] @ lis1

Both give the expected result:

{{{a1, c1, e1}, {a2, c2, e2}}, {{a3, c3, e3}, {a4, c4, e4}}}

ReplaceAt was introduced in V 13.1 and has the advantage that we can use the usual Condition syntax. Example:

ReplaceAt[lis1, x_ /; SymbolName[x] != "b1" :> Nothing, {All, All, {2, 4}}]

{{{a1, b1, c1, e1}, {a2, c2, e2}}, {{a3, c3, e3}, {a4, c4, e4}}}

$\endgroup$
1
$\begingroup$

Another way using ReplaceAll and Span:

(lis1 /. x_?VectorQ :> x[[1 ;; 5 ;; 2]]) === lis2

(*True*)

Or using ReplaceAll and Select:

(lis1 /. x_?VectorQ :> Select[x, OddQ[Det@Position[x, #]] &]) === lis2

 (*True*)

Thanks to @eldo for showing me the following shorter way:

  (lis1 /. x_?VectorQ :> x[[;; ;; 2]]) === lis2

  (*True*)
$\endgroup$
2
  • 1
    $\begingroup$ Or, even shorter, lis1 /. x_?VectorQ :> x[[;; ;; 2]] +1 $\endgroup$
    – eldo
    Commented Sep 15, 2023 at 6:20
  • $\begingroup$ Thanks, mate! :-) $\endgroup$ Commented Sep 15, 2023 at 6:27
1
$\begingroup$

Using list structure provided:

lis1 = {{{a1, b1, c1, d1, e1}, {a2, b2, c2, d2, e2}}, {{a3, b3, c3, 
    d3, e3}, {a4, b4, c4, d4, e4}}}

then

Transpose /@ (Part[#, {1, 3, 5}] &@*Transpose /@ lis1)

yields:

{{{a1, c1, e1}, {a2, c2, e2}}, {{a3, c3, e3}, {a4, c4, e4}}}
$\endgroup$
0
$\begingroup$

the data I would like to select are not in an consecutive order


Since DeleteCases retains list structure, it is suitable for this task.

Clear["Global`&*"]
lis1 = {{{a1, b1, c1, d1, e1}, {a2, b2, c2, d2, e2}}, {{a3, b3, c3, 
     d3, e3}, {a4, b4, c4, d4, e4}}};

DeleteCases[lis1, 
 a_Symbol /; StringStartsQ[ToString@a, "b" | "d"], All]

{{{a1, c1, e1}, {a2, c2, e2}}, {{a3, c3, e3}, {a4, c4, e4}}}


If the symbols are in random order; e.g.,

lis2 = lis1 /. v_?VectorQ :> RandomSample[v, Length@v]
{{{b1, e1, c1, a1, d1}, {d2, a2, c2, e2, b2}}, {{c3, b3, d3, e3, 
   a3}, {b4, c4, e4, d4, a4}}}
DeleteCases[lis2, 
 a_Symbol /; StringStartsQ[ToString@a, "b" | "d"], All]

{{{e1, c1, a1}, {a2, c2, e2}}, {{c3, e3, a3}, {c4, e4, a4}}}

$\endgroup$

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.