0
votes

How can one complete the FizzBuzz exercise in Codingbat with just a return statement?

The code that I last used to solve the problem was:

public String[] fizzBuzz(int start, int end) {
  String[] a = new String[end - start];
  for(int i = start; i < end; i++) a[i - start] = i % 15 == 0 ? "FizzBuzz" : i % 3 == 0 ? "Fizz" : i % 5 == 0 ? "Buzz" : String.valueOf(i);
  return a;
}

My goal is to have code that looks something like this:

public String[] fizzBuzz(int start, int end) {
  return foo;
}

Problem

This is slightly more difficult version of the famous FizzBuzz problem which is sometimes given as a first problem for job interviews. (See also: FizzBuzz Code.) Consider the series of numbers beginning at start and running up to but not including end, so for example start=1 and end=5 gives the series 1, 2, 3, 4. Return a new String[] array containing the string form of these numbers, except for multiples of 3, use "Fizz" instead of the number, for multiples of 5 use "Buzz", and for multiples of both 3 and 5 use "FizzBuzz". In Java, String.valueOf(xxx) will make the String form of an int or other type. This version is a little more complicated than the usual version since you have to allocate and index into an array instead of just printing, and we vary the start/end instead of just always doing 1..100.


Test Cases

fizzBuzz(1, 6) → ["1", "2", "Fizz", "4", "Buzz"]
fizzBuzz(1, 8) → ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7"]
fizzBuzz(1, 11) → ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz"]
fizzBuzz(1, 16) → ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz"]
fizzBuzz(1, 4) → ["1", "2", "Fizz"]
fizzBuzz(1, 2) → ["1"]
fizzBuzz(50, 56) → ["Buzz", "Fizz", "52", "53", "Fizz", "Buzz"]
fizzBuzz(15, 17) → ["FizzBuzz", "16"]
fizzBuzz(30, 36) → ["FizzBuzz", "31", "32", "Fizz", "34", "Buzz"]
fizzBuzz(1000, 1006) → ["Buzz", "1001", "Fizz", "1003", "1004", "FizzBuzz"]
fizzBuzz(99, 102) → ["Fizz", "Buzz", "101"]
fizzBuzz(14, 20) → ["14", "FizzBuzz", "16", "17", "Fizz", "19"]
3
This question is better suited to codegolf.stackexchange.com - jrook
@jrook I'll post it there as well then. - pythx
There is already an answer on that website: codegolf.stackexchange.com/questions/58615/1-2-fizz-4-buzz - jrook
@jrook Mine is not looking for the smallest way to do it. I simply want a way that is compatible with Codingbat and only uses the return statement. - pythx

3 Answers

3
votes

Not sure exactly why you'd want to do this in a single return statement but nevertheless here it goes:

return IntStream.range(start, end)
                .mapToObj(i -> i % 15 == 0 ? "FizzBuzz" : 
                          i % 3 == 0 ? "Fizz" : i % 5 == 0 ? "Buzz" : String.valueOf(i))
                .toArray(String[]::new);
  1. IntStream.range returns a sequential ordered IntStream from start (inclusive) to end (exclusive) by an incremental step of 1 which fits exactly in the manner of your imperative approach.
  2. mapToObj enables us to convert the IntStream to a Stream<String>.
  3. toArray enables us to convert the Stream<String> to a String[] for return.

you can read more about the IntStream API here.

1
votes

The only way that I could imagine without any Java 8 features involves some ugly conversions of arrays to strings, and strings of arrays of strings to arrays of strings with some very ... pragmatic regular expressions. But I guess the solution is not supposed to be pretty anyhow. It passes all the test cases, though, so it achieves all the goals that can be achieved with test-driven development...

Never write anything even remotely resembling this in real life!

import java.util.Arrays;

public class OneLineFizzBuzz
{
    public static void main(String[] args)
    {
        OneLineFizzBuzz f = new OneLineFizzBuzz();
        String[] result = f.fizzBuzz(1000, 1006);
        System.out.println(Arrays.toString(result));

        check(f.fizzBuzz(1, 6), new String[]{"1", "2", "Fizz", "4", "Buzz"});
        check(f.fizzBuzz(1, 8), new String[]{"1", "2", "Fizz", "4", "Buzz", "Fizz", "7"});
        check(f.fizzBuzz(1, 11), new String[]{"1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz"});
        check(f.fizzBuzz(1, 16), new String[]{"1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz"});
        check(f.fizzBuzz(1, 4), new String[]{"1", "2", "Fizz"});
        check(f.fizzBuzz(1, 2), new String[]{"1"});
        check(f.fizzBuzz(50, 56), new String[]{"Buzz", "Fizz", "52", "53", "Fizz", "Buzz"});
        check(f.fizzBuzz(15, 17), new String[]{"FizzBuzz", "16"});
        check(f.fizzBuzz(30, 36), new String[]{"FizzBuzz", "31", "32", "Fizz", "34", "Buzz"});
        check(f.fizzBuzz(1000, 1006), new String[]{"Buzz", "1001", "Fizz", "1003", "1004", "FizzBuzz"});
        check(f.fizzBuzz(99, 102), new String[]{"Fizz", "Buzz", "101"});
        check(f.fizzBuzz(14, 20), new String[]{"14", "FizzBuzz", "16", "17", "Fizz", "19"});        
    }
    private static void check(String[] fizzBuzz, String[] strings)
    {
        boolean passed = Arrays.equals(fizzBuzz, strings);
        System.out.println(Arrays.toString(fizzBuzz) + " passed? " + passed);
        if (!passed)
        {
            System.out.println("Whoopsie...");
        }
    }

    public String[] fizzBuzz(int start, int end)
    {
        return (start == end ? ""
            : (start % 15 == 0 ? "FizzBuzz"
                : start % 3 == 0 ? "Fizz"
                    : start % 5 == 0 ? "Buzz" : String.valueOf(start))
                + Arrays.toString(fizzBuzz(start + 1, end)))
                    .replaceAll("\\]", "").split("\\[|,\\s*");
    }
}
0
votes
  1. make sure you have JDK 8(Otherwise this code will not work)

  2. Using IntStream.range you can generate integers. and once you have a panch of numbers you have to map them accordingly. (in this case, we have to map them into String [] and check for multiple 3, multiple 5 and multiple 3 & 5 too) Now, for the rest of the numbers Using String.valueof() we can add them to the Array.

N.B: make sure to put FIZZBUZZ on the top since it's an if statement only one of them gets executed.

    public static String[] foo(int start, int end) {
        return IntStream.range(start, end).mapToObj(i-> ( 
        i%5==0 && i%3==0 ) ? "FIZZBUZZ": 
        i%3==0 ? "FIZZ":
        i%5==0 ? "BUZZ": 
        String.valueOf(i)).toArray(String[]::new);
}