13
\$\begingroup\$

In many programming languages, the floating-point value NaN, or "not a number", in some programming languages generated by the expression 0/0, does not compare as equal to itself. In this challenge, you have to take input as five vulgar fractions, each matching \-?\d+\/\d+ (for example, 2/3, -1/5, or even 4/0).

Your program should output the size of the largest group or groups with equal numbers. For example,

1/2
2/4
4/8
1/3
2/6

will output 3, since the first three fractions form a group, and so do the last two, but three is larger so we choose it.

If every fraction is unequal and there is at least one non-0/0 value, output 1. However, if every value is 0/0, output 0.

Here is the full algorithm to determine if two fractions are equal.

  1. 0/0 does not equal any other fraction, not even another 0/0 (NaN).
  2. All instances of (positive number)/0 are equal (infinity).
  3. All instances of (negative number)/0 are equal (-infinity).
  4. If there are no zero-denominator fractions, compare them as usual.

More examples:

1/3,4/12,2/14,3/21,4/28 -> 3
1/1,1/1,1/1,1/1,3/4 -> 4
1/1,1/1,1/1,1/1,1/1 -> 5
1/1,1/1,-1/1,-1/1,-1/1 -> 3
1/2,2/4,-3/6,-4/8,-5/10 -> 3
-1/1,-1/1,-1/1,-1/1,-1/1 -> 5
-1/2,-2/4,1/2,2/4,1/1 -> 2
-1/2,-2/4,1/2,2/4,-5/10 -> 3
1/8,2/16,3/24,5/40,10/80 -> 5
1/1,2/1,3/1,4/1,5/1 -> 1
1/2,2/4,1/0,263/0,2837/0 -> 3
0/0,0/0,0/0,0/0,0/0 -> 0
1/0,2/0,3/0,4/0,5/0 -> 5
1/0,2/0,3/0,-1/0,-2/0 -> 3
-1/2,0/0,0/0,0/0,0/0 -> 1
-1/5,-2/10,0/0,0/0,0/0 -> 2

This is , so fewest bytes wins!

\$\endgroup\$
3
  • 6
    \$\begingroup\$ Must we take five strings or may we accept five pairs of integers? May we use a character (or characters) other than / for our division operator (e.g. our language's natural one)? \$\endgroup\$ Commented Jun 22 at 17:31
  • 3
    \$\begingroup\$ Are potential inaccuracies caused by floating-point data types acceptable? \$\endgroup\$
    – Luis Mendo
    Commented Jun 22 at 22:51
  • \$\begingroup\$ Should 5/010,1/2 output 2 (because 5/10 == 1/2) or 1 or undefined (because 010 is interpreted in at least some but not all languages as octal 10, aka 8 [e.g. python pre PEP 3127, node.js, I thought C and presumably java, but python post PEP 3127 will throw a SyntaxError]) \$\endgroup\$
    – Foon
    Commented Jun 24 at 13:23

13 Answers 13

5
\$\begingroup\$

JavaScript (ES6), 53 bytes

Expects an array of strings such as ["1/3","4/12","2/14",...].

a=>Math.max(...a.map(o=x=>o[x=eval(x)]=x==x&&-~o[x]))

Try it online!

Commented

a =>              // a[] = input array
Math.max(         // return the maximum value:
  ...a.map(o =    //   o = object to keep track of counters
    x =>          //   for each value x in a[]:
    o[            //     update o[x]
      x = eval(x) //     where x is first eval()'uated
    ] =           //     to:
      x == x &&   //       false if x is NaN
      -~o[x]      //       or o[x] + 1 otherwise
  )               //   end of map()
)                 // end of Math.max()

Without eval(), 54 bytes

Takes an array of [numerator, denominator] pairs.

a=>Math.max(...a.map(o=([x,y])=>o[x/=y]=x==x&&-~o[x]))

Try it online!

\$\endgroup\$
4
\$\begingroup\$

Python 3.8 (pre-release),  134  133 bytes

-1 byte: if i[-2:]>'/0'elseif'/0'<i[-2:]else.

lambda*x:(s:=[eval(i)if'/0'<i[-2:]else'n+-'[round((n:=eval(i[:-2]))/(abs(n)+.1))]for i in x])and max([(j!='n')*s.count(j)for j in s])

Takes input like f('-1/5', '-2/10', '0/0', '0/0', '0/0').
Try it online!

Explanation

lambda*x:                                                                                                                               # Defines lambda
         (s:=[                                                                             ])                                           # Walrus operator
              eval(i)                                                                                                                   # Evaluates fraction...
                     if'/0'<i[-2:]                                                                                                      # ...if the denominator isn't 0
                                  else'n+-'[                                    ]                                                       # Otherwise, choose one of 3 characters
                                            round((n:=eval(i[:-2]))/(abs(n)+.1))                                                        # chosen by the sign of the numerator
                                                                                 for i in x                                             # Do this for each of the 5 arguments
                                                                                             and                                        # Ignores first argument since it's truthy
                                                                                                               s.count(j)               # Count number of times each item appears
                                                                                                      (j!='n')*                         # ...if it isn't 0/0 --> 'n'
                                                                                                     [                   for j in s]    # Do this for each item in s
                                                                                                 max(                               )   # Finds the largest count
\$\endgroup\$
4
\$\begingroup\$

MATL, 6 bytes

U&=sX>

Try it online! Or verify all test cases.

How it works

U    % Implicit input. Convert to numerical vector
&=   % Matrix of pair-wise equality comparisons
s    % Sum of each column
X>   % Maximum. Implicit display
\$\endgroup\$
3
  • \$\begingroup\$ The code internally converts to floating-point values, which can cause numerical inaccuracies. OP hasn't confirmed if that's allowed or not, but other answers assume it is... \$\endgroup\$
    – Luis Mendo
    Commented Jun 23 at 20:41
  • 1
    \$\begingroup\$ So effectively max(sum( arr[i] == arr[j] )) where i and j both span the whole range, so every number gets compared to itself (so NaNs count as zero matches)? That's the algorithm I was thinking of implementing in C or asm, was looking at other answers to see if there was any flaw in it. Like we want infinities to count as equal to other infinities of the same sign, etc. and the OP's rules are the same as IEEE 754 FP math (if we ignore rounding error). \$\endgroup\$ Commented Jun 23 at 23:12
  • 1
    \$\begingroup\$ @PeterCordes Yes, that's what the code does: essentially, let the IEEE 754 format do all the work :-) Each signed infinity automatically equals itself, and NaN is automatically different from anything, even itself. You can see an Octave version of this code in my comment here \$\endgroup\$
    – Luis Mendo
    Commented Jun 24 at 9:35
2
\$\begingroup\$

Jelly, 11 bytes

⁾/÷yⱮV⁼þ`SṀ

A monadic Link that accepts the list of strings and yields the count.

Try it online!

How?

⁾/÷yⱮV⁼þ`SṀ - Link: list of lists of characters A
⁾/÷         - list of characters -> "/÷"
    Ɱ       - map across A with:
   y        -   translate (replace '/' with '÷')
     V      - evaluate as Jelly code
        `   - use that as both arguments of:
       þ    -   table of:
      ⁼     -     equal?
         S  - sum (columns)
          Ṁ - maximum
\$\endgroup\$
2
\$\begingroup\$

Uiua SBCS, 14 bytes

/↥⊂0⊕⧻⊛.▽≠NaN.

Try it!

/↥⊂0⊕⧻⊛.▽≠NaN.­⁡​‎‎⁡⁠⁣⁡‏⁠‎⁡⁠⁣⁢‏⁠‎⁡⁠⁣⁣‏⁠‎⁡⁠⁣⁤‏⁠‎⁡⁠⁤⁡‏⁠‎⁡⁠⁤⁢‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁢⁡‏⁠‎⁡⁠⁢⁢‏⁠‎⁡⁠⁢⁣‏⁠‎⁡⁠⁢⁤‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁣‏⁠‎⁡⁠⁤‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁡‏⁠‎⁡⁠⁢‏‏​⁡⁠⁡‌­
        ▽≠NaN.  # ‎⁡remove NaNs (0/0s only)
    ⊕⧻⊛.        # ‎⁢group by length of each value
  ⊂0            # ‎⁣prepend zero so max of empty list is zero instead of ¯∞
/↥              # ‎⁤maximum
\$\endgroup\$
2
\$\begingroup\$

R, 53 bytes (as a script)

max(0,table(sapply(parse(,,commandArgs()[-1]),eval)))

Explanation

max(                              # max between 0 and contingency table (can be -inf)
  0,                              # by default max return -Inf if all Nan so a 0 corrects this
  table(                          # contingency table of number of occurences
    sapply(                       # map te expression list to eval
      parse(                      # parse input as an expression() list
        ,,commandArgs()[-1]),     # input args
      eval)))                     # eval evaluates the fraction to double

Extra:

If you accept a function then the code is 41 bytes long. In this case the input is a semicolon-separated string.

Try it!

\(x)max(0,table(sapply(parse(,,x),eval)))
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Welcome and nice first answer! Functions are allowed by default, so that's ok. You are also encouraged to add a link to an online REPL so anyone can quickly test you solution (eg. ATO!). \$\endgroup\$
    – pajonk
    Commented Jun 24 at 8:51
2
\$\begingroup\$

Haskell, 53 45 bytes

xM cnT<(wx<l*^jn eqo<m(gk$(/)<ν<*ʃ"/"*^ν))

Attempt This Online!

Using the approach of Luis' MATL answer. Semi-ungolfed Pseudocode:

parseFraction = gk $ (/) < ν <* ʃ"/" <*> read

-- elementwise equality
eqo :: Eq a => [a] -> [a] -> [Bool]
eqo = liftA2 (==)

f = maxBy count < splitAt length < (join eqo < m parseFraction)
\$\endgroup\$
4
  • \$\begingroup\$ Nice. You can read fractions for cheaper using parsers: gk$(/)<ν<*ʃ"/"*^ν. Using this should save 5 bytes overall. \$\endgroup\$
    – Wheat Wizard
    Commented Jul 14 at 15:30
  • \$\begingroup\$ You can map and take the max at the same time using xM, so mx<m cnT can be xM cnT. \$\endgroup\$
    – Wheat Wizard
    Commented Jul 14 at 15:36
  • \$\begingroup\$ You can avoid using (**) to save 1 more byte. With the above the code would look like: xM cnT<(wx<l*^jn eqo<m(gk$(/)<ν<*ʃ"/"*^ν)). Since a**b$c is the same as a<b*^c. \$\endgroup\$
    – Wheat Wizard
    Commented Jul 14 at 15:41
  • \$\begingroup\$ Thank you, your suggestions are very valuable. \$\endgroup\$
    – corvus_192
    Commented yesterday
1
\$\begingroup\$

Retina 0.8.2, 81 bytes

\d+
$*
G`1
+r`(1*)(\3)*\b/(1+)\b
$#2,$3/$1
1+/
;
O`
m`^(.+)(¶\1)*$
1$#2$*
O^`
\G1

Try it online! Takes input on separate lines but link is to test suite that splits on commas for convenience. Explanation:

\d+
$*

Convert to unary.

G`1

Remove 0/0 entries.

+r`(1*)(\3)*\b/(1+)\b
$#2,$3/$1

Convert the remaining entries to continued fractions.

1+/
;

Remove the trailing n/0 remnant.

O`

Sort the continued fractions.

m`^(.+)(¶\1)*$
1$#2$*

Count how many there are of each, in unary.

O^`

Sort descending.

\G1

Convert the largest to decimal, but if there were only 0/0 fractions, then there is nothing left at this point, so we get a final result of 0.

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

Octave, 63 bytes

Anonymous function which takes a row vector of fractions as its input.

@(x)max([sum([y=isinf(x)&x>0;y&x<0]'),~isnan([c,f]=mode(x))*f])

Try it online!

That started off nice and short, and then ballooned!

It is based around the mode function to calculate the frequency of elements.

Annoyingly Octave's mode function seems to have a bug in it whereby it doesn't treat inf as being equal to inf. So [~,f]=mode([inf inf inf]) returns 1. This differes from MATLAB proper which returns 3 for the same thing. As a result we have to do a lot of extra work to count the number of positive and negative infinities.

@(x)
    max([                     % The largest count overall.
         sum([                % Row-wise sum the infinity checks to get counts of negative and positive infinities.
              y=isinf(x)&x>0; % Check for positive infinities (logical array)
              y&x<0           % Check for negative infinities (logical array)
             ]'),
         ~isnan(              % Check if the most common element is NaN (only true if all NaN)
                [c,f]=mode(x) % Find the most common element and how many of it there are.
               )*f            % 0 if all NaN, or element count otherwise
        ])

Without this mode bug, it would be 27 characters:

@(x)~isnan([c,f]=mode(x))*f
\$\endgroup\$
1
  • \$\begingroup\$ Wouldn't something like this work (translation of my MATL answer)? \$\endgroup\$
    – Luis Mendo
    Commented Jun 23 at 17:30
1
\$\begingroup\$

Charcoal, 41 bytes

≔EE⪪S,⮌I⪪ι/×⊟ι⎇Σι∕¹Σι≕math.infθI⌈EθΣEθ⁼ιλ

Try it online! Link is to verbose version of code. Explanation:

≔EE⪪S,⮌I⪪ι/×⊟ι⎇Σι∕¹Σι≕math.infθ

Convert the fractions into floating-point values but using -inf, nan or inf as appropriate.

I⌈EθΣEθ⁼ιλ

Take the Cartesian product of the list with itself, compare each pair of elements, take sums, and output the maximum.

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

05AB1E, 25 bytes

…0/0Kε'/¡`©_i.±«ë®/]{γéθg

Input as a list of strings.

Try it online or verify all test cases.

Explanation:

Unfortunately, dividing by 0 in 05AB1E or 05AB1E (legacy) acts as a no-op, so will result in the nominator itself when done manually or the string itself when using evals (in Elixir, Python or Batch), instead of the for this challenge preferred -INF/NaN/INF. So instead, things have to be done manually..

…0/0K       # Remove any "0/0" items from the (implicit) input-list
ε           # Map over the remaining fractions:
 '/¡       '#  Split it on "/"
    `       #  Pop and push the values of the pair to the stack
     ©      #  Store the top value (the denominator) in variable `®` (without popping)
      _i    #  Pop and if this is 0:
        .±  #   Get the sign of the nominator (-1 if <0; 0 if 0; 1 if >0)
          « #   Append that to each value in the (implicit) input-list
       ë    #  Else (we're not dividing by 0):
        ®/  #   Simply divide the nominator by the denominator `®`
]           # Close both the if-else statement and map
 {          # Sort the mapped values
  γ         # Split it into equal adjacent groups
   é        # Sort these groups by length
    θ       # Pop and keep the last/longest group
     g      # Pop and push its length

Some minor equal-bytes alternatives:

  • ε...©...ë®/ could be ε...ëy.E: evaluate [.E] the current string of the map [y] as Elixir code.
  • éθg could be €gà: get the length of each group [€g] and leave the maximum [à] of those.

PS: {γéθg cannot be D.M¢ (Duplicate [D] the list; pop and push the most frequent item [.M]; get the count of that in the list ¢) to save a byte, because it won't work correctly with inner lists (caused by the «). And although the « could alternatively be for +1 byte, then D.M¢ would still incorrectly result in [] if the input only contains "0/0" items.

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

MATLAB, 28 bytes

x=num2str(x);max(sum(x==x'))

How it works

  • Given an input char e.g. x='1/3,4/12,2/14,3/21,4/28'
  • Convert it to a numeric array
  • Use implicit expansion to make a matrix comparing all elements to each other
  • sum to get the count of how many elements each is equal to (including itself)
  • max to get the desired output

The question doesn't (currently) stipulate the input must be a string, if the input were an array of values [1/3,4/12,2/14,...] then the num2str isn't needed and this drops to 15 bytes.

\$\endgroup\$
3
  • \$\begingroup\$ Hey, nice to see you around here! I like your approach :-) However, you need to handle input, that is, you can't assume the input is in variable x. So you have to define a function or use input \$\endgroup\$
    – Luis Mendo
    Commented Jun 26 at 19:39
  • \$\begingroup\$ @Luis so would have to be @(x)max(sum(num2str(x)==num2str(x)'))? \$\endgroup\$
    – Wolfie
    Commented Jun 27 at 6:12
  • \$\begingroup\$ Yes, something like that. You could save a byte with n=@num2str;@(x)max(sum(n(x)==n(x)')). Or, in Octave, see my comment to Tom Carpenter's answer \$\endgroup\$
    – Luis Mendo
    Commented Jun 27 at 8:37
0
\$\begingroup\$

Haskell, 56 40 bytes

-16 bytes thanks to Wheat Wizard

xMl<bg<fl(jn eq)<m(gk$(/)<ν<*ʃ"/"*^ν)

Attempt This Online!

Semi-ungolfed:

parseFraction = gk $ (/) < ν <* ʃ"/" *^ ν
f = lengthOfLargest < toBag < filter (join (==)) < map parseFraction
\$\endgroup\$
2
  • \$\begingroup\$ I'm not sure why there are 2 hgl answers but this one can be shortened as well using the tricks I've commented on the other one plus the xMl function. xMl<bg<fl(jn eq)<m(gk$(/)<ν<*ʃ"/"*^ν) \$\endgroup\$
    – Wheat Wizard
    Commented Jul 14 at 15:51
  • \$\begingroup\$ I simply couldn't decide which approach I liked more and since I had already golfed both to see which was shorter I decided to post both \$\endgroup\$
    – corvus_192
    Commented yesterday

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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