5
$\begingroup$

If I wish to select numbers which are greater than 2 or less than 1, I use the following codes respectively:

Select[{1, 2, 4, 7, 6, 2, -2, 3, 9, -0.2, 0.4}, #1 > 2 & ]

(*{4, 7, 6, 3, 9}*)

Select[{1, 2, 4, 7, 6, 2, -2, 3, 9, -0.2, 0.4}, #1 < 1 & ]

(*{-2, -0.2, 0.4}*)

My questions are:

1) How do I select a pair of numbers which differ by 2

2) How do I select a pair of numbers which differ by AT LEAST 3

3) How do I select three numbers with a total that is greater than 10

$\endgroup$
  • $\begingroup$ Could you please clarify what you mean by "pair of numbers which differ by 2". Given a list {1,2,4,7,6,8,9}, do you seek the output: {{2,4}, {6,8}}, or the output {{2,4}, {4,6}, {6,8}, {7,9}} ?? I would have thought that your terminology 'pair' suggested the former, but perhaps you seek the latter. $\endgroup$ – wolfies Sep 7 '15 at 5:55
  • $\begingroup$ The latter @wolfies $\endgroup$ – thils Sep 7 '15 at 6:23
12
$\begingroup$
DeleteDuplicates[Sort /@ With[{s = Subsets[list, {2}]}, Select[s, Abs[Subtract @@ #] == 2 &]]]

DeleteDuplicates[Sort /@ With[{s = Subsets[list, {2}]}, Select[s, Abs[Subtract @@ #] >= 3 &]]]

DeleteDuplicates[Sort /@ With[{s = Subsets[list, {3}]}, Select[s, Total@# > 10 &]]]

Look up the functions used in the documentation, experiment with them. This is basic stuff... As an aside, this can be done with pattern matching operations, that would be a good exercise to get an understanding of that if you need it.

Per your comment question, here's a simple example of the first case using pattern matching:

ReplaceList[list, {___, a_, ___, b_, ___} /; Abs[a - b] == 2 :> {a, b}]

In English, this says "Find all pairs in the list, where the difference is 2, and replace the list with that pair", the end result being the list of those replacements. The {___, a_, ___, b_, ___} defines a pattern. There are some good tutorials in the docs, search for "pattern", "pattern matching", etc.

$\endgroup$
  • 1
    $\begingroup$ The documentation did not provide examples where u combine five functions: "DeleteDuplicate", "Sort", "With", "Subsets" & "Select"...so anything but basic. And what do u mean by "pattern matching operations"??? $\endgroup$ – thils Sep 6 '15 at 22:35
  • $\begingroup$ @thils: That's what I meant by experimenting - of course the docs won't have an example for something like "give me all pairs of some set that differ by at least...", that's just too specific. By experimenting with the functions I used, you'll quickly get to where you think of a problem and you just intuit how to combine them. As for pattern matching, I'll just add a simple example to the answer. Hope that clarified my statement, no slight intended. $\endgroup$ – ciao Sep 6 '15 at 22:47
  • 1
    $\begingroup$ Still don't understand how u experiment if u don't know the 5 functions to start off with....its OK, if one is dealing with smaller no. of functions. $\endgroup$ – thils Sep 6 '15 at 22:53
  • 2
    $\begingroup$ @thils: Well, that's part of learning the language - searching the docs, poking around at functions and playing with them. $\endgroup$ – ciao Sep 6 '15 at 22:57
  • 1
    $\begingroup$ I was expecting an answer that only involved "Select" and no more for my questions.....the options for "Select" may be inadequate?? Perhaps this why "poke & play" is being required. I terminate my responses on this issue with this. $\endgroup$ – thils Sep 6 '15 at 23:15
7
$\begingroup$

Since you want to work with pairs of numbers, you can create pairs and operate on them. For example,

lst={1, 2, 4, 7, 6, 2, -2, 3, 9, -0.2, 0.4};

To select a pair of numbers which differ by 2

Select[Partition[lst, 2, 1], #[[2]] - #[[1]] == 2 &]    

To select a pair of numbers which differ by at least 3

Select[Partition[lst, 2, 1], Abs[#[[2]] - #[[1]]] > 3 &]
$\endgroup$
3
$\begingroup$

Using Subset is the best way to go about this, since you have to test every pair (or every triplet) of numbers from the list, and Subset gets you that list of pairs (or triplets) as fast as possible.

Here is another method, and while it performs twice as many tests as it has to, it performs the test at the same time that it is forming the subsets, so perhaps there may be some advantage to it in some cases. In addition, I like the readability of it, although ciao's solution is also very readable. (Update: I think in some cases, this method will find extra solutions. I am working on a fix.)

If the list is

list = {1, 2, 4, 7, 6, 2, -2, 4, 3, 9, -0.2, 0.4};

then we first DeleteDuplicates on the list

list = DeleteDuplicates @ list

since it, for instance, {4, 2} will be tested, so obviously we don't need more than one 4 and 2.

For differences of 2:

Flatten[
  Outer[
   If[#1 - #2 == 2, {##}, Unevaluated@Sequence[]] &
   , list
   , list
  ]
  , 1]
(* {{4, 2}, {6, 4}, {3, 1}, {9, 7}} *)

For differences greater than 3:

Outer[
 If[#1 - #2 >= 3, {##}, Unevaluated@Sequence[]] &
 , list
 , list
]
, 1] ~Flatten~ 1

For the sum of triplets greater than 10:

DeleteDuplicates@Flatten[
  Outer[
    If[10 < Total@{##}, Sort@{##}, Unevaluated@Sequence[]] &
    , list
    , list
    , list
  ]
  , 2];

In Mathematica 10.2, you can replace Unevaluated@Sequence[] with Nothing.

Update

Interestingly enough, this method doesn't perform any better than the most straight-forward way of just making the table, and of course it's also worse than ciao's answer:

 f = If[Subtract@## == 2, Sort@{##}, Unevaluated@Sequence[]] &

 list = Range[1000];
 Outer[f, list, list]~Flatten~1; // AbsoluteTiming // First
 Table[f[list[[i]], list[[j]]], {i, 1, Length@list}, {j, 1, i}] ~Flatten~ 1; // AbsoluteTiming // First
 DeleteDuplicates[Sort /@ With[{s = Subsets[list, {2}]}, Select[s, Abs[Subtract @@ #] == 2 &]]]; // AbsoluteTiming // First
 (* 2.1285 *)
 (* 1.7366 *)
 (* 1.0545 *)

The problem compounds with more dimensions:

f = If[10 < Total@{##}, Sort@{##}, Unevaluated@Sequence[]] &;

DeleteDuplicates@Flatten[Outer[f, list, list, list], 2]; // AbsoluteTiming // First
DeleteDuplicates@Flatten[Table[f[list[[i]], list[[j]], list[[kk]]], {i, 3, Length@list}, {j, 2, i - 1}, {kk, 1, j - 1}], 2]; // AbsoluteTiming // First
DeleteDuplicates[Sort /@ With[{s = Subsets[list, {3}]}, Select[s, Total@# > 10 &]]]; // AbsoluteTiming // First
(* 5.0851 *)
(* 1.1571 *)
(* 0.5956 *)
$\endgroup$
  • $\begingroup$ @bbgodfrey. Since this implementation of Outer will pick three elements from the same list, one of the choices it will make is the single 4 from each copy of list. Try it with list = {4}. But this brings up a different problem. If elements of the list aren't allowed to be repeated, then this method will find extra solutions. E.g. if the list is {4, 4, 3}, it will find {4, 4, 4} along with {4, 4, 3} even though the former is not a subset of the list. I will have to re-think the method a little bit. $\endgroup$ – march Sep 7 '15 at 19:00
  • $\begingroup$ Thanks for the clarification. I see that you are correct, and that I misunderstood your solution. I shall delete my earlier comments. I hope that you can resolve the extra solutions, because your approach otherwise is quite elegant. $\endgroup$ – bbgodfrey Sep 7 '15 at 19:24

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.