Eduardo Portet
Eduardo Portet

Reputation: 287

Substitute statements in code with loops in Java

I have these two pieces of code:

    int prevY = 0;
    // this is the function InsertionSort applied to i
    StdDraw.setPenColor(Color.blue);
    for (int i = 1; i <= N; i++) {
        int x = i;
        int y = runInsertion(i);
        int prevX = i - 1;
        StdDraw.setPenRadius(lineRadius);
        StdDraw.line(prevX, prevY, x, y);
        StdDraw.setPenRadius(pointRadius);
        StdDraw.point(x, y);
        prevY = y;
    }

    prevY = 0;
    // this is the function SelectionSort applied to i
    StdDraw.setPenColor(Color.black);
    for (int i = 1; i <= N; i++) {
        int x = i;
        int y = runSelection(i);
        int prevX = i - 1;
        StdDraw.setPenRadius(lineRadius);
        StdDraw.line(prevX, prevY, x, y);
        StdDraw.setPenRadius(pointRadius);
        StdDraw.point(x, y);
        prevY = y;
    }

They both do the same thing except for a minor change in the color that will be used and in the sorting algorithm that will be used.

Is there any way to make an array for the colors and the sorting algorithms like:

String[] algorithms = {"runInsertion", "runSelection"}
String[] colors = {"blue", "black"};

And then with a for loop call the appropriate index so that the code has been shortened.

I know this will not work as I proposed it, but I just want to know if there is a way or a specific method that lets me do this.

Upvotes: 2

Views: 216

Answers (4)

Steve K
Steve K

Reputation: 4921

You can simply make a method which you can call with parameters to invoke the options that you want. In java 8 you can even refer to the different algorithms (runInsertion(i) and runSelection(i)) as method references which work as lambdas.

public void sortWithAlgorithm(Color color, Function<Integer, Integer> algorithm) {
    int prevY = 0;
    StdDraw.setPenColor(color);
    for (int i = 1; i <= N; i++) {
        int x = i;
        int y = algorithm.apply(i);
        int prevX = i - 1;
        StdDraw.setPenRadius(lineRadius);
        StdDraw.line(prevX, prevY, x, y);
        StdDraw.setPenRadius(pointRadius);
        StdDraw.point(x, y);
        prevY = y;
    }
}

And then to invoke the two, you can make a couple convenience methods:

void sortInsertion (){
    sortWithAlgorithm(Color.Blue, this::runInsertion);
}

void sortSelection() {
    sortWithAlgorithm(Color.Black, this::runSelection);
}

Upvotes: 1

NicholasFolk
NicholasFolk

Reputation: 1137

Yes, one possible way is using a Function object (unfortunately, it is not as easy as inputing the method variable name since methods are not first class objects as they are in a language like Javascript).

A Function class in Java looks like this:

public class Function<T,V> {   // T is a generic for your input type
    abstract V apply(T input);    // V is a generic for your output type
}

Then it is as easy as extracting your code into a method where you input a color string and the corresponding Function object (Sounds like a good job for a Map!) The only caveat with the following implementation is that I'm not exactly sure how runSelection and runInsertion are implemented, but I'm going off the idea that they take in an int and output an int.

// Make the map somewhere earlier in the code
Map<String, Function<Integer, Integer> map =  new HashMap();
map.put("blue", new Function<Integer, Integer>(){ 
    Integer apply(Integer input) {
        return runInsertion(input);
    }
}
map.put("black", new Function<Integer, Integer>(){ 
    Integer apply(Integer input) {
        return runSelection(input);
    }
}

for (Entry<String, Function<Integer, Integer>> entry : map.entrySet()) {
    doExtractedMethod(entry.getKey(), entry.getValue());
}

...

public void doExtractedMethod(String color, Function<Integer, Integer> function) {

    int prevY = 0;
    // this is the function InsertionSort applied to i
    StdDraw.setPenColor(color);      // COLOR USED HERE
    for (int i = 1; i <= N; i++) {
        int x = i;
        int y = function.apply(i);   // FUNCTION USED HERE
        int prevX = i - 1;
        StdDraw.setPenRadius(lineRadius);
        StdDraw.line(prevX, prevY, x, y);
        StdDraw.setPenRadius(pointRadius);
        StdDraw.point(x, y);
        prevY = y;
    }
} 

Upvotes: 0

vbezhenar
vbezhenar

Reputation: 12336

Just extract your logic into method with required parameters:

void work(Color color, Function<Integer, Integer> algorithm) {
    int prevY = 0;
    StdDraw.setPenColor(color);
    for (int i = 1; i <= N; i++) {
        int x = i;
        int y = algorithm.apply(i);
        int prevX = i - 1;
        StdDraw.setPenRadius(lineRadius);
        StdDraw.line(prevX, prevY, x, y);
        StdDraw.setPenRadius(pointRadius);
        StdDraw.point(x, y);
        prevY = y;
    }
}

and call it:

work(Color.blue, this::runInsertion);
work(Color.black, this::runSelection);

or for arrays:

List<Function<Integer, Integer>> algorithms = Arrays.asList(this::runInsertion, this::runSelection);
List<Color> colors = Arrays.asList(Color.blue, Color.black);

for (int i = 0; i < algorithms.size(); i++) {
    work(colors.get(i), algorithms.get(i));
}

Upvotes: 1

Sam
Sam

Reputation: 9944

The 'Design pattern' approach to this problem is called the Template method. It involves creating an abstract class for your algorithm, which would define and implement, for example, methods step1() and step3(), and an abstract method step2() to be implemented in different ways by different implementations of the algorithm. However, that seems like overkill for your purposes. It might be simplest just to reduce some of your duplication by using, say, a draw(x, y) method to contain the lines:

StdDraw.setPenRadius(lineRadius);
StdDraw.line(prevX, prevY, x, y);
StdDraw.setPenRadius(pointRadius);
StdDraw.point(x, y);

Upvotes: 1

Related Questions