# Reflect manipulations on one list in a second list

I'd like to mirror the manipulations (specifically deletion, insertion, and reassignment) done at each position of two equally-sized lists, based on the contents of only one of those lists. As an example say I have

l1 = {a, b, c, 4, e, f, 7, 8, i}
l2 = {1, 2, 3, 4, 5, 6, 7, 8, 9}


and then I want to remove all the numbers from the l1, then also remove elements at the same positions in l2 yielding

l1={a,b,c,e,f,i}
l2={1,2,3,5,6,9}


I can achieve this specific behavior by creating a selector list according to the conditions imposed on the first list and then applying Pick to both, like

sel[x_List] := Table[! MatchQ[ic, _?NumberQ], {ic, x}]

Pick[l1,sel[l1]]
Pick[l2,sel[l1]]


The above yields the correct l1 and l2. The function sel can also be used in a more cumbersome fashion with Insert and Part for insertion and reassignment, but all of this seems janky and my heart insists there is a more elegant way. Is this the best that can be done?

I should also note that it cannot be assumed that elements being removed from both lists are equal, nor are the lists canonically ordered. The only safe assumptions are that the lists are equally sized, and that the operation performed at position n in l1 should be repeated at position n in l2 (but determined only by the value at position n in l1).

• The obvious (and perhaps uncomfortable) solution is working with l = Transpose[{l1,l2}] .... – Dr. belisarius Nov 11 '15 at 3:03
• When using Pick this might be more straight forward: Pick[l2, NumericQ /@ l1, False] – Mike Honeychurch Nov 11 '15 at 3:06
• ...and there's always Position[] to fall back on. – J. M.'s technical difficulties Nov 11 '15 at 3:11

test=NumericQ /@ l1


This can be used with Pick

Pick[l2, test, False]


If you want positions you could always use Position directly

pos=Position[l1, _?NumericQ]
Delete[l1, pos]


or use Pick again to get positions and test for True or False depending on what you want to do:

Pick[Range[Length[l1]],test,True|False]


and/or

List /@ Pick[Range[Length[l1]],test,True|False]


...depending on what format you require

• With Position[], I imagined something like pos = Position[l1, x_ /; ! NumericQ[x], 1, Heads -> False]; Extract[#, pos] & /@ {l1, l2}. – J. M.'s technical difficulties Nov 11 '15 at 3:19
• @J.M. My answer was a bit terse but with Position I was thinking more in terms of using with Delete – Mike Honeychurch Nov 11 '15 at 3:35
• Oh, of course; with Delete[] you don't need to negate the expression test. :) – J. M.'s technical difficulties Nov 11 '15 at 3:59
• I'm down voting because this answer seems to make an incorrect assumption about the generation of the dependent list. Also, it doesn't seem any simpler for the specific manipulation it address than the one presented in the question, but that's a matter of opinion. – IPoiler Nov 11 '15 at 18:12
• @IPoiler I based my answer on finding the positions because that was where the OP needed some work. What you do with the positions once found is straight forward using Delete, Insert and Part – Mike Honeychurch Nov 11 '15 at 21:51

In the vein of @belisariushassettled's comment, the lists can be joined as an array to have the rows operated on after Transpose.

l1 = {a, b, c, 4, e, f, 7, 8, i}
l2 = {1, 2, 3, 4, 5, 6, 7, 8, 9}
l=Transpose[{l1,l2}]


## Deletion

Example: Remove based on positions of l1 which contain integers:

ld=Transpose@DeleteCases[l, {_Integer, _}];
l1=ld[]
l2=ld[]

{a,b,c,e,f,i}
{1,2,3,5,6,9}


## Insertion

Example: Insert elements after positions in l1 which contain integers:

li=Transpose@Insert[l, {y, z}, Position[l, {_Integer, _}] + 1];
l1=li[]
l2=li[]

{a,b,c,4,y,e,f,7,y,8,y,i}
{1,2,3,4,z,5,6,7,z,8,z,i}


## Reassignment

Example: Transform elements to letters at positions where l1 contains integers:

lr=Transpose@ReplaceAll[l, {x_Integer, y_} :> {FromLetterNumber[x],FromLetterNumber[x + 1]}];
l1=lr[]
l2=lr[]

{a,b,c,d,e,f,g,h,i}
{1,2,3,e,5,6,h,i,9}