15
\$\begingroup\$

In this question, we will only focus on losing weight by doing exercise, although there are still many ways to lose weight.

Different sports burn different amount of calories.

For example, playing billiards for an hour can burn 102 calories[1], while playing basketball for 15 minutes can already burn 119 calories [1], which make weight loss by playing basketball easier, at least from some perspectives.

The exact way to weigh the easiness is by dividing the amount of calories burnt by the time needed, which gives us the easiness index (EI).

For example, fencing for 15 minutes can burn 85 calories, which gets an EI of 85/15.

You will be given a list in this format:

[["fencing",15,85],["billiards",60,102],["basketball",15,119]]

or other format that you want.

Then, you will output the sports which have the highest EI.

TL;DR

Given a list of tuples [name,value1,value2] output the name where value2/value1 is the highest.

Constraints

  • You may not produce any real number that is not integer in the process.
  • You may not use any fraction built-in.

Specifications (Specs)

  • If there is more than one name that satisfy the result, you may output any non-empty subset of them or any element of them.
  • The name will match the regex /^[a-z]+$/, meaning that it will only consist of lowercase Latin standard alphabet.
  • The list will not be empty.

Testcase

Input:

[["fencing",15,85],["billiards",60,102],["basketball",15,119]]

Output:

basketball

References

  1. http://calorielab.com/burned/
\$\endgroup\$
  • 1
    \$\begingroup\$ Is it OK if dividing integers in our language produces a fractional type by default? \$\endgroup\$ – xnor Jul 21 '16 at 6:47
  • 1
    \$\begingroup\$ 1. yes 2. fraction built-in \$\endgroup\$ – Leaky Nun Jul 21 '16 at 6:49
  • 5
    \$\begingroup\$ Isn't this do X without Y? \$\endgroup\$ – Martin Ender Jul 21 '16 at 7:31
  • 4
    \$\begingroup\$ Do you mean "How to lose weight easily?" not "How to weight loss easily?".. \$\endgroup\$ – Insane Jul 21 '16 at 20:55
  • 3
    \$\begingroup\$ @LeakyNun Right.. inside jokes on titles.. because the majority of people read it as bad grammar :P \$\endgroup\$ – Insane Jul 21 '16 at 22:57

18 Answers 18

13
\$\begingroup\$

Python 2, 51 bytes

lambda l:max((10**len(`l`)*a/b,s)for s,b,a in l)[1]

Does the obvious thing of finding the entry with the biggest ratio, but sidesteps the prohibition against floats by first multiplying the numerator by a huge input-dependent power of 10 before floor-dividing.

I'll prove this coefficient is big enough to make floor-division act the same difference as non-floor division.

Claim: If a1/b1 > a2/b2, then floor(Na1/b1) > floor(Na2/b2) for any N≥b1b2.

Proof: Note that a1/b1 - a2/b2 is a multiple of 1/b1b2, so a1/b1 - a2/b2 > 0 implies that

a1/b1 - a2/b2 ≥ 1/b1b2

Then, multiplying both sides by N,

Na1/b1 - Na2/b2 ≥ N/b1b2 ≥ 1

So, since Na1/b1 and Na2/b2 differ by at least 1, their respective floors are distinct. ∎

Now, note that the product b1b2 has digit length at most their total digit length, which is less than the string length of the input. Since the input is in base 10, its suffices to use 10 to the power of its length N=10**len(`l`) to produce a number with more digits than it, guaranteeing the condition.

\$\endgroup\$
  • \$\begingroup\$ Any chance e.g. 9 might work instead of 10? \$\endgroup\$ – Lynn Jul 21 '16 at 8:20
  • 2
    \$\begingroup\$ @Lynn Unfortunately, it fails for huge inputs like [('y', 10**296+1, 1), ('x', 10**296, 1)]. \$\endgroup\$ – xnor Jul 21 '16 at 8:30
8
\$\begingroup\$

JavaScript (ES6), 43 bytes

a=>a.sort(([p,q,r],[s,t,u])=>q*u-r*t)[0][0]

Or alternatively

a=>a.sort((v,w)=>v[1]*w[2]-v[2]*w[1])[0][0]

Sort is of course overkill for this, but reduce would take 46 bytes:

a=>a.reduce((v,w)=>v[1]*w[2]-v[2]*w[1]?v:w)[0]
\$\endgroup\$
7
\$\begingroup\$

MATL, 8 bytes

pG/*&X<)

All computed numbers are integer values. First, the product of the denominators is computed (this is an integer). This product is divided by each denominator (which gives an integer too). Each result is then multiplied by the corresponding numerator. This gives an integer value proportional to the original fraction.

Input format is: numeric array with denominators, numeric array with numerators, cell array of strings with sport names:

[85, 102, 119]
[15, 60, 15]
{'fencing', 'billiards', 'basketball'}

If there are several minimizers the first one is output.

Try it online!

p     % Take first input. Compute the product of its entries
G/    % Divide by first input element-wise
*     % Take second input. Multiply by previous array element-wise
&X<   % Argmax
)     % Take third input. Index into it using previous result. Display
\$\endgroup\$
5
\$\begingroup\$

Dyalog APL, 18 bytes

⎕⊃⍨(⊢⍳⌈/)⎕×(∧/÷⊢)⎕

Prompts for times, then for calories, then for activity names.

prompt (for times)

(∧/÷⊢) LCM ∧/ of the times divided by ÷ the times (so no floats)

⎕× prompt (for calories) and multiply by them

(⊢⍳⌈/) in that , get the position of the maximum value ⌈/

⎕⊃⍨ prompt (for activities), then pick the nth.

Example run:

      ⎕⊃⍨(⊢⍳⌈/)⎕×(∧/÷⊢)⎕
⎕:
      15 60 15
⎕:
      85 102 119
⎕:
      'fencing' 'billiards' 'basketball'
basketball
\$\endgroup\$
4
\$\begingroup\$

Brachylog, 42 bytes

:{bh.}a*g:?z:2aott.
[D:[S:I:J]]tt:D*:I/:S.

Try it online!

/ above is integer division because both J*D and I are integers (D is a multiple of I in fact).

Explanation

  • Main predicate: Input = [["string":mins:cals]:...]

    :{bh.}a*                Multiply all mins in the Input together
            g:?z            Zip that number with the Input
                :2a         Apply predicate 2 to that zipped list
                   ott.     Sort the list of lists on the values of the first element of
                              sublists, Output is the string of the last sublist
    
  • Predicate 1:

    [D:[S:I:J]]             Input = [D:[S:I:J]]
               tt:D*        Multiply J by D
                    :I/     Divide the result by I
                       :S.  Output = [That number:S]
    
\$\endgroup\$
3
\$\begingroup\$

Retina, 64 62 bytes

Byte count assumes ISO 8859-1 encoding.

\d+
$*
%`\G1
0
1
:$_:
Ts`0p¶`0_`:.+?:
+`(0+) \1
@$1 
O`
!`\w+$

Input is one sport per line, with the format value1 value2 name. Output is one of the maximal results (if there's a tie it will give the one with the largest value1 and if those are tied as well if will give the lexicographically larger name).

Note that this is super slow (for the exact same reasons as yesterday's Stack Exchange outage). To make it run in a reasonable amount of time, you can add a \b in front of the (0+) (which won't affect the way it processes the input at all but severely limits the backtracking of that regex). I've done that in the test link below.

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Python 2, 55 54 bytes

lambda x:sorted(x,lambda(S,N,D),(s,n,d):N*d-n*D)[0][0]

Thanks to @xnor for golfing off 1 byte!

Test it on Ideone.

\$\endgroup\$
  • \$\begingroup\$ Nice! I forgot that sorted can take a two-input comparator function, I was going to hack that together. \$\endgroup\$ – xnor Jul 21 '16 at 6:53
  • \$\begingroup\$ Seems like it's shorter to unpack lambda(a,b,c),(d,e,f):b*f-c*e. \$\endgroup\$ – xnor Jul 21 '16 at 6:57
  • \$\begingroup\$ @xnor Neat! I didn't know you could do that. \$\endgroup\$ – Dennis Jul 21 '16 at 6:58
2
\$\begingroup\$

Haskell 72 70 bytes

import Data.List
(n,(x,y))%(m,(a,b))=compare(x*b)$y*a
fst.minimumBy(%)

Usage :

main=putStr$(fst.minimumBy(%))[("fencing",(15,85)),("billiards",(60,102)),("basketball",(15,119))]
\$\endgroup\$
1
\$\begingroup\$

Mathematica, 46 bytes

Last/@MaximalBy[#,g=LCM@@First/@#;g#2/#&@@#&]&

The order of the tuples should be {value1,value2,name}. Returns the full set of all maximal results.

I work around the use of fractions by multiplying the numerator by the LCM of all value1s before the division.

\$\endgroup\$
1
\$\begingroup\$

R, 42 40 bytes

function(v)v[which.max(v[,3]%/%v[,2]),1]

Takes input in the form of a data frame with column types of string (it also works with factors), numeric, numeric.

  • %/% is integer division.

This is my first submission, let me know if it's within the rules.

Edit: Turns out you don't need the braces to define a one-line function.

\$\endgroup\$
  • \$\begingroup\$ Might this give the wrong answer if two similar ratios divide to the same integer, e.g. 7/3,9/4? \$\endgroup\$ – Neil Jul 21 '16 at 19:08
  • \$\begingroup\$ My understanding is if they divide to the same integer, you can output any of them, this will output the first in data frame. \$\endgroup\$ – Azor Ahai Jul 21 '16 at 19:10
1
\$\begingroup\$

C++14, 89 bytes

Lambda function:

[](auto s,int*a,int*b,int l){int r=--l;while(l--)r=b[l]*a[r]>a[l]*b[r]?l:r;return s[r];};

Ungolfed:

[](auto s,int*a,int*b,int l)
{
  int r = --l;
  while(l--)
    r = b[l] * a[r] > a[l] * b[r] ? l : r;
  return s[r];
};

Usage:

#include <iostream>

int main()
{
  const char* s[] = {"fencing", "billiards", "basketball"};
  int a[] = {15,60,15};
  int b[] = {85,102,119};
  std::cout << [](auto s,int*a,int*b,int l){int r=--l;while(l--)r=b[l]*a[r]>a[l]*b[r]?l:r;return s[r];}(s,a,b,3);
}
\$\endgroup\$
1
\$\begingroup\$

Haskell, 46 bytes

s(n,(x,y))=(divMod y x,n)
g =snd.maximum.map s

EDIT: This solution doesn't work as pointed out by Damien this doesn't solve the problem. I'm searching a nice fix.

\$\endgroup\$
  • 1
    \$\begingroup\$ s(_,(x,y))=divMod y x is shorter \$\endgroup\$ – Damien Jul 22 '16 at 6:47
  • 1
    \$\begingroup\$ s(n,(x,y))=(divMod y x,n) g=snd.maximum.map s too.. \$\endgroup\$ – Damien Jul 22 '16 at 7:34
  • 2
    \$\begingroup\$ But this does not solve the problem as divMod a b < divMod c d is not equivalent to a/b < c/d. divMod 19 4 < divMod 55 12 but 19/4 > 55/12 \$\endgroup\$ – Damien Jul 22 '16 at 7:54
  • \$\begingroup\$ Mmmh indeed my solution is quite poor… I'll think of nice fix, thanks ! \$\endgroup\$ – villou24 Jul 22 '16 at 8:47
1
\$\begingroup\$

VBA Excel, 109 bytes

Function A(B)
R=1
For I=2 To B.Rows.Count
If B(R,2)*B(I,3)>B(I,2)*B(R,3) Then R=I
Next
A=B(R,1)
End Function

Invoke in spreadsheet cell referencing a table of activities and parameters:

enter image description here

\$\endgroup\$
1
\$\begingroup\$

05AB1E, 6 7 bytes

P¹÷*ZQÏ

+1 byte to bugfix my divmod approach (see this comment on another answer) by porting @LuisMendo's MATL answer, so make sure to upvote him!

Input is similar as his answer: three separated lists, being an integer-list of denominators; an integer-list of nominators; and a string-list of names.

Try it online or verify some more test cases.

Explanation:

P       # Take the product of the (implicit) input-list of denominators
        #  i.e. [85,102,119] → 1031730
 ¹÷     # (Integer)-divide it by each of the denominators of the first input-list
        #  i.e. 1031730 / [85,102,119] → [12138,10115,8670]
   *    # Multiply each (at the same positions) by the (implicit) input-list of nominators
        #  i.e. [12138,10115,8670] * [15,60,15] → [182070,606900,130050]
    Z   # Get the maximum of this list (without popping the list itself)
        #  i.e. [182070,606900,130050] → [182070,606900,130050] and 606900
     Q  # Check which values are equal to this maximum
        #  i.e. [182070,606900,130050] and 606900 → [0,1,0]
      Ï # Only leave the strings of the (implicit) input-list of names at the truthy indices
        #  i.e. ["fencing","billiards","basketball"] and [0,1,0] → ["billiards"]
        # (after which the result is output implicitly)
\$\endgroup\$
0
\$\begingroup\$

Java 8, 128 Bytes

String f(List<Object[]>l){return l.stream().max((x,y)->(int)x[2]*1000/(int)x[1]-(int)y[2]*1000/(int)y[1]).get()[0].toString();}
\$\endgroup\$
0
\$\begingroup\$

Ruby, 72 bytes

e=0;while gets;n=$_.split;f=eval n[2]+"/"+n[1];m,e=n[0],f if f>e;end;p m

I really thought this would be shorter...

Input is taken from STDIN in the format of name time calories

Oh well, any help to shorten it is appreciated.

\$\endgroup\$
0
\$\begingroup\$

Clojure, 63 bytes

#((last(sort(fn[[x a b][y c d]](-(* b c)(* a d)))%))0)
\$\endgroup\$
0
\$\begingroup\$

PHP, 98 bytes

Used a simpler input format than the example, just like this:

fencing,15,85,billiards,60,102,basketball,15,119

$s=explode(",",$argn);for($x=0;$s[$x];$x+=3){if($y<$e=$s[$x+2]/$s[$x+1]){$y=$e;$z=$s[$x];}}echo$z;

Try it online!

\$\endgroup\$

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