Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have two lists, say a and b, both of length n. I'd like to compute the following:

  • minimum of $a[i]/b[i]$ where $i=1, 2, ...n$ and $b[i]>0$

I'd also like to know the index of the element where the min occurs.

share|improve this question
    
Do you want the i to be from the original list? Or the list of ratios with the b[i]=0 indices removed? –  Gabriel Nov 29 '13 at 1:56
    
I want the i from the original list. –  user10831 Dec 2 '13 at 20:35
add comment

6 Answers

n = 10000;
{a, b} = RandomReal[{-1, 1}, {2, n}];

This may be quite fast:

r = a/b; Position[r, min = Min@Pick[r, Positive@b]]
min
{{7955}}
-850.273
share|improve this answer
    
But Kuba you can't do the division "a/b" in first place if there was a zero in list "b" ? A check is needed before –  Nasser Nov 29 '13 at 0:47
1  
@Nasser If you won't tell anybody then it is ok :P because later only Positive b positions are picked. So even ComplexInfinity is not a problem. But it is good point to keep in mind, for a general approach/condition. –  Kuba Nov 29 '13 at 0:49
add comment

I would do this by first combining the lists using Transpose, and then filtering the division pairs using either a pattern with Cases or a predicate using Select

Cases[Transpose[{a, b}], {_, _?Positive}]

or

Select[Transpose[{a, b}], #[[2]] > 0&]

This will return the filtered list of {numerator, denominator} pairs, to get the divisions I would just expand on the above with Map Apply (@@@)

lst = Divide @@@ Cases[Transpose[{a, b}], {_, _?Positive}]

or

lst = Divide @@@ Select[Transpose[{a, b}, #[[2]] > 0&]

This will give back a list with the defined ratios. You can then just use Min and Position as other answers have shown.

share|improve this answer
add comment

One way to enforce the positivity condition on b is to locate the positions of all the positive elements of b and use those to index into the division of a by b.

a = RandomReal[{-10, 10}, 10];
b = RandomReal[{-10, 10}, 10];
pos = Flatten[Position[b, _?(0 < # &)]]
Min[a[[pos]]/b[[pos]]]
share|improve this answer
    
But Bill you can't do the division "a/b" in first place if there was a zero in list "b" ? A check is needed before. –  Nasser Nov 29 '13 at 0:46
    
No it is not ignored, try Min[{1, 2/0}] it looks ignored because in pos there are no entries with b=0. –  Kuba Nov 29 '13 at 7:08
    
I've rearranged things so it now only does the division on the nonzero terms. –  bill s Nov 29 '13 at 14:44
add comment
a = RandomReal[{1, 10}, 10];
b = RandomReal[{1, 10}, 10];
lst = a/b;

Min[lst]
(*0.442821447015283*)

Position[lst, Min[lst]]
(* {{4}} *)

Update to answer comment below

How can I implement the b[i]>0 condition

One way can be to use MapThread to make the list by checking for the condition

a = {2, 9, 5, 3, 0, 4, 9, 1};
b = {0, -4, 2, 0, 10, 4, 0, 10};
lst = MapThread[If[#2 > 0, #1/#2, Sequence @@ {}] &, {a, b}]

(*{5/2, 0, 1, 1/10}*)

Min[lst]
(* 0 *)

Position[lst, %]
{{2}}

Updated to return position of min in original list not filtered list

remember the index while filtering to use it to go back.

a = {2, 9, 5, 3, 0, 4, 9};
b = {0, -4, 2, 0, 10, 4, 0};
i = 0;
lst = MapThread[(i++; If[#2 > 0, {i, #1/#2}, Sequence @@ {}]) &, {a,b}]

(* {{3, 5/2}, {5, 0}, {6, 1}, {8, 1/10}} *)

min = Min[lst[[All, 2]]]
(* 0 *)

p = Flatten@Position[lst[[All, 2]], min];
lst[[p, 1]]
(* {5} *)

A short hand version is

i = 0;
p = Flatten@
 Position[lst[[All,2]],Min@MapThread[(i++;If[#2>0,{i,#1/#2},Sequence@@{}])&,{a,b}][[All,2]]]
lst[[p, 1]]
share|improve this answer
    
How can I implement the b[i]>0 condition? –  user10831 Nov 29 '13 at 0:19
    
The actual position is 5, not 2. –  rm -rf Nov 29 '13 at 4:57
add comment

If the minimum can be assumed to be unique then use f1, which returns the position of only the first occurrence of the minimum value. Otherwise use f2, which is slower but returns the positions of all occurrences.

f1[a_,b_] := With[{i = Ordering[#1,1][[1]]}, {#1[[i]],#2[[i]]}]& [a[[#]]/b[[#]],#]& @
                  SparseArray[UnitStep[-b], Automatic, 1]["AdjacencyLists"];
f2[a_,b_] := With[{m = Min[#1]}, {m,Pick[#2,#1,m]}]& [a[[#]]/b[[#]],#]& @
                  SparseArray[UnitStep[-b], Automatic, 1]["AdjacencyLists"];
n = 7;
a = {2, 9, 5, 3,  0, 0, 9};
b = {0,-4, 2, 0, 10, 4, 0};
f1[a,b]
f2[a,b]

{0, 5}
{0, {5, 6}}

share|improve this answer
    
Ray, would you mind to add some definitions of a, b etc. to make evaluation unambiguous? –  Yves Klett Nov 29 '13 at 7:37
add comment

EDIT

After Kuba appropriate comment (and using his code for picking Min) to deal with positive denominator:

f[a_, b_] := Quiet[{s = Position[a/b, Min@Pick[a/b, Positive@b]], 
  Extract[(a/b), First@s]}]

Note test case with two cases:

f[{1, 2, 3, 3}, {1, -1, 2, 3}]

yields:

{{{1}, {4}}, 1}

The First@s just to displaythe (unique) value of minimum. Quiet to suppress errors of Indeterminate for 0/0 and ComplexInfinity nonzero/0. Still works for these cases.

share|improve this answer
    
@Kuba fair enough –  ubpdqn Nov 29 '13 at 8:26
    
I mean, I like that approach, just correct it so it fits the OP's need :) –  Kuba Nov 29 '13 at 8:27
    
@Kuba I appreciate feedback and have modified code, purloing your code (with attribution):) –  ubpdqn Nov 29 '13 at 8:43
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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