7
$\begingroup$

Consider

DeleteCases[{{1, 2, 3, 4}, {1, 3, 4, 5}}, {_, 3, __}]

{{1, 2, 3, 4}}

i.e., keep only those lists that don't have 3 on their second position. That works well.

Now,

DeleteCases[{{3, 5, 7, 5, 2}, {1, 2, 3, 4, 5}, {1, 3, 4, 5}}, {__, 3, __}]

{{3, 5, 7, 5, 2}}

gives only those lists that don't have 3 somewhere in the middle, i.e. on positions 2, 3 or 4 (or, in other words, keeps only those lists where 3 is in positions 1 or 5).


Question

How to make a general pattern/function that will keep only those lists (of arbitrary length n) that don't have a given number a on a specific position k($1\leq k\leq n$)?

$\endgroup$

6 Answers 6

6
$\begingroup$

I have implemented this function. For the cases I have checked it worked well.

fun[list_, k_, a_] := DeleteCases[list, Table[_, k - 1]~Join~{a}~Join~{___}]

For eg: fun[{{1, 2, 3}, {3, 2, 4}, {1, 2, 3, 4, 5, 6, 7, 8}, {7, 8, 4, 3}, {1, 2}}, 3, 3] gives {{3, 2, 4}, {7, 8, 4, 3}, {1, 2}}

$\endgroup$
11
$\begingroup$

Repeated takes arguments to specify how many times a pattern should repeat. Questions 1 and 2 didn't specify that there should be an element following the given number a, as in the opening example, so I wasn't sure whether ___ (no element needs to follow) or __ (at least one element should follow) should be specified. But it's easy to change.

(* matches if  a  is at end of list *)
pos[a_, k_Integer?Positive] := {Repeated[_, {k - 1}], a, ___};

DeleteCases[{{3, 5, 7, 5, 2}, {1, 2, 3, 4, 5}, {1, 3, 4, 5}, {1, 3, 3}}, pos[3, 3]]
  (*{{3, 5, 7, 5, 2}, {1, 3, 4, 5}}  *)

DeleteCases[{{3, 5, 7, 5, 2}, {1, 2, 3, 4, 5}, {1, 3, 4, 5}, {1, 3, 3}}, pos[3, 1]]
(*  {{1, 2, 3, 4, 5}, {1, 3, 4, 5}, {1, 3, 3}}  *)

For large arrays, a vectorized approach with numeric boolean operations will be more efficient. Example:

SeedRandom[1];
data = RandomInteger[3, {15, 5}];

Block[{k = 3, a = 3},
 Pick[data, Unitize[data[[All, k]] - a], 1] (* drops element if a is in k-th position *)
 ]
(*
  {{3, 1, 0, 1, 1}, {0, 0, 0, 1, 3}, {0, 0, 0, 0, 2}, {0, 1, 2, 0, 0},
   {0, 0, 1, 3, 0}, {2, 0, 1, 1, 3}, {3, 3, 2, 3, 2}, {1, 0, 1, 0, 3},
   {2, 0, 1, 3, 2}, {1, 2, 0, 0, 0}, {2, 1, 2, 1, 0}, {2, 3, 1, 1, 1}}
*)
$\endgroup$
8
$\begingroup$

EDIT: Per Mr. Wizard's recommendation, added additional checks

del[data_List, position_Integer?Positive, val_] :=
 DeleteCases[data, _?(Length[#] >= position && #[[position]] == val &)]

SeedRandom[1];

data = RandomInteger[10, {5, 10}]

(*  {{1, 4, 0, 7, 0, 0, 8, 6, 0, 4}, 
     {1, 8, 5, 1, 1, 1, 3, 2, 10, 1}, 
     {6, 0, 2, 6, 4, 5, 4, 3, 0, 1}, 
     {3, 5, 3, 0, 3, 2, 3, 9, 5, 1}, 
     {5, 2, 3, 9, 1, 0, 4, 4, 1, 5}}  *)

del[data, 3, 3]

(*  {{1, 4, 0, 7, 0, 0, 8, 6, 0, 4}, 
     {1, 8, 5, 1, 1, 1, 3, 2, 10, 1}, 
     {6, 0, 2, 6, 4, 5, 4, 3, 0, 1}}
$\endgroup$
3
  • $\begingroup$ This is the method I typically use, however consider adding a Length check to avoid e.g. {1, 2}[[3]], i.e. Length[#] >= position && #[[position]] == val $\endgroup$
    – Mr.Wizard
    Commented Sep 19, 2016 at 9:46
  • 1
    $\begingroup$ An alternative one might use is MatchQ[#[[position]], val] instead of #[[position]] == val, and then val could be any pattern. One should beware that with ==, elements will match that are sufficiently close numerically to be considered equal, whereas with MatchQ, they have to be exactly the same. So == will be a superior approach in some applications and not in others. $\endgroup$
    – Michael E2
    Commented Sep 19, 2016 at 10:49
  • $\begingroup$ @Mr.Wizard - edited per your recommendation. Thanks. $\endgroup$
    – Bob Hanlon
    Commented Sep 19, 2016 at 19:01
3
$\begingroup$

Using Michael's data:

list = {{3, 5, 7, 5, 2}, {1, 2, 3, 4, 5}, {1, 3, 4, 5}, {1, 3, 3}};

Function definition

del[{e_, p_}][list_] /; list[[p]] == e := Nothing
del[_][list_] := list

Expected results:

del[{3, 3}] /@ list

{{3, 5, 7, 5, 2}, {1, 3, 4, 5}}

del[{3, 1}] /@ list

{{1, 2, 3, 4, 5}, {1, 3, 4, 5}, {1, 3, 3}}

$\endgroup$
2
$\begingroup$

Using SequenceReplace:

list = {{3, 5, 7, 5, 2}, {1, 2, 3, 4, 5}, {1, 3, 4, 5}, {3}, {1, 
    2}, {3, 3}};

SequenceReplace[list, {{Repeated[_, 1], 3, b___}} :> Nothing]

{{3, 5, 7, 5, 2}, {1, 2, 3, 4, 5}, {3}, {1, 2}}

$\endgroup$
1
$\begingroup$

Using Michael's data:

list = {{3, 5, 7, 5, 2}, {1, 2, 3, 4, 5}, {1, 3, 4, 5}, {1, 3, 3}};

Function definition using Select:

FilterByPositionValue[l_List, val_, pos_Integer] := Select[l, #[[pos]] =!= val &]

Testing FilterByPositionValue:

FilterByPositionValue[list, 3, 3]

(*{{3, 5, 7, 5, 2}, {1, 3, 4, 5}}*)

FilterByPositionValue[list, 3, 1]

(*{{1, 2, 3, 4, 5}, {1, 3, 4, 5}, {1, 3, 3}}*)
$\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.