# Mark selected sub-lists in the list they were selected from

I've got this simple problem with two lists. I select some items from a list, but I want to visualize the difference between the previous list and the list that I create with Select.

For instance:

a = {{7, 0, 0, 2}, {0, 0, 2, 5}, {10, 4, 8, 7}, {7, 1, 9, 2}, {1, 3, 6, 7},
{6, 9, 2, 9}, {2, 0, 7, 1}, {2, 5, 1, 1}, {9, 6, 4, 0}, {9, 9, 2, 8}};
b = Select[a, #[[4]] > 5 &];


I want a list that compare the two lists in this manner

results =
{{7, 0, 0, "-"}, {0, 0, 2, "-"}, {10, 4, 8, 7}, {7, 1, 9, "-"}, {1, 3, 6, 7},
{6, 9, 2, 9}, {2, 0, 7, "-"}, {2, 5, 1, "-"}, {9, 6, 4, "-"}, {9, 9, 2, 8}};

• An easy way is : {#[[1]], #[[2]], #[[3]], If[#[[4]] > 5, #[[4]], "-"]} & /@ a. – b.gates.you.know.what Mar 25 '13 at 11:34

results = a /. {x__, _?(# <= 5 &)} :> {x, "-"}


or

a /. {x___, y_ /; y <= 5} :> {x, "-"}


or

b = Select[a, #[[4]] > 5 &];
results=If[MemberQ[b, #], #, Flatten@{#[[;; -2]], "-"}] & /@ a


or

results=a; MapAt[If[# <= 5, "-", #] &, results, {All, -1}]


to get

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

• I was going to post a /. {x___, y_} /; y <= 5 -> {x, "-"} – Dr. belisarius Mar 25 '13 at 11:40
• @belisarius, fwiw, of the three variants of ReplaceAll, a /. {x___, y_} /; y <= 5 -> {x, "-"}, a /. {x___, y_ /; y <= 5} :> {x, "-"} and  a /. {x___, _?(# <= 5 &)} :> {x, "-"} the middle one seems to be marginally faster for large lists. – kglr Mar 25 '13 at 12:09
• Interesting, I wonder why :) – Dr. belisarius Mar 25 '13 at 12:27
• @kguler; @b.gatessucks; @belisarius Thanks a lot. You're very kind and solved my problem in a very smart way. I hope I'll be usefull to you. – meriens Mar 25 '13 at 13:43

Why Select? Traverse the list with Map and replace the appropriate part of each sublist if it fails your test.

Map[If[#[[4]] > 5, #, ReplacePart[#, 4 -> "-"]] &, a]


Using Reap and Sow with tags, you can get both the selected elements and the diff output in one go:

{selected, diff} = Last@Reap[
Cases[a, x_ :> If[x[[4]] > 5, Sow[x, "selected"],
Sow[ReplacePart[x, 4 -> "-"], "diff"]]], {"selected", "diff"}] ~Flatten~ 1

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


If you want the selected elements too in your diff output, then all you need to do is to also tag them "diff", i.e., change the first Sow above to Sow[x, {"selected", "diff"}].

If you have both lists prepared already, you can use SequenceAlignment and then post-process:

Flatten[
SequenceAlignment[a, b] /. {deleted_List, {}} :>
Map[MapAt["-" &, #, -1] &, deleted],
1]


This however may not be the optimal solution for really large lists in terms of performance.