8
$\begingroup$

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}};
$\endgroup$
  • 2
    $\begingroup$ An easy way is : {#[[1]], #[[2]], #[[3]], If[#[[4]] > 5, #[[4]], "-"]} & /@ a. $\endgroup$ – b.gates.you.know.what Mar 25 '13 at 11:34
10
$\begingroup$
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}} *)
$\endgroup$
  • $\begingroup$ I was going to post a /. {x___, y_} /; y <= 5 -> {x, "-"} $\endgroup$ – Dr. belisarius Mar 25 '13 at 11:40
  • $\begingroup$ @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. $\endgroup$ – kglr Mar 25 '13 at 12:09
  • $\begingroup$ Interesting, I wonder why :) $\endgroup$ – Dr. belisarius Mar 25 '13 at 12:27
  • $\begingroup$ @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. $\endgroup$ – meriens Mar 25 '13 at 13:43
3
$\begingroup$

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]
$\endgroup$
3
$\begingroup$

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"}].

$\endgroup$
2
$\begingroup$

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.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.