Compute ratios of elements in two lists

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.

-
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

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

-
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
@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

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]]]

-
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

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.

-
a = RandomReal[{1, 10}, 10];
b = RandomReal[{1, 10}, 10];
lst = a/b;

Min[lst]
(*0.442821447015283*)

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


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@
lst[[p, 1]]

-
How can I implement the b[i]>0 condition? – user10831 Nov 29 '13 at 0:19
The actual position is 5, not 2. – R. M. Nov 29 '13 at 4:57

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[[#]],#]& @
f2[a_,b_] := With[{m = Min[#1]}, {m,Pick[#2,#1,m]}]& [a[[#]]/b[[#]],#]& @
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}}

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

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.

-
@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