GaelDev
GaelDev

Reputation: 85

ArrayList optimization

i am currently working on this for personal gratification and would like some advice on how i can make this code faster :

I have one ArrayList composed of an object note, which have coordinates and color value stored in it.

Each "note" is created in real time during the rendering call.

I have made this function :

void keyPressed() {  
    if (key == 's' || key == 'S') {
        PImage img = createImage(posX, specSize, RGB);
        for(int x = 0; x < posX; x++){
            for(int y = 0; y < specSize; y++){
                for(int i = 0; i < notes.size(); i++){
                    if( (notes.get(i).getX() == x) 
                         && (notes.get(i).getY() == y) ){

                        int loc = x + y*posX;
                        img.pixels[loc] = color(notes.get(i).getR(),
                                    notes.get(i).getG(), notes.get(i).getB());
                    }
                }
            }
        }
    img.updatePixels();
    img.save("outputImage.png");
    }
}

So when i press the "S" key, i run a loop on the width and height because they can be different in each run, and then on my arrayList and get the corresponding "note" with it's x and y position. then i write my picture file. As you can imagine, this is really, really, slow...

Around 5 to 6 minutes for a 1976x256px file. For me it's okay but it would be great to shorten this a little.

Is there a way to optimize this three loops? If you need more code, please let me know it's a small code and i don't mind.

Upvotes: 1

Views: 108

Answers (4)

Amir Pashazadeh
Amir Pashazadeh

Reputation: 7302

Create a class such as Point with two properties of x and y and implement proper equals and hashcode methods as:

public class Point {
    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        Point point = (Point) o;

        if (x != point.x)
            return false;
        if (y != point.y)
            return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }
}

now put the Point as key of a map, and find your points using this, so you don't have to iterate over the whole lists.

Upvotes: 0

einnocent
einnocent

Reputation: 3964

Convert your list of notes into a structure mapped like

Map<Integer, Map<Integer, Note> noteMap

Then replace your inner-most loop with a single call like

yNoteMap = note.get(x);

if (yNoteMap != null) {

note = yNoteMap.get(y);

if (note != null) {

// do stuff with note

}

}

Your computational complexity will go from about O(n^3) to O(n^2).

Upvotes: 0

tgkprog
tgkprog

Reputation: 4598

Can clone notes (and any other object that is used to save) and do this in a different thread so its async to UI. the code will take same or more time but the user can use the rest of the app. Clone is neccesary as you want a snap shot of state when save was clicked.

Dont make a thread put use a ThreadPoolExecutor with one thread max. In the run method could apply what David suggested - one loop instead of two.

Upvotes: 1

Dawood ibn Kareem
Dawood ibn Kareem

Reputation: 79838

How about this?

void keyPressed() {  
    if (key == 's' || key == 'S') {
        PImage img = createImage(posX, specSize, RGB);
        for(int i = 0; i < notes.size(); i++){
            int x = notes.get(i).getX();
            int y = notes.get(i).getY();
            int loc = x + y*posX;
            img.pixels[loc] = color(notes.get(i).getR(),
                           notes.get(i).getG(), notes.get(i).getB());
        }
        img.updatePixels();
        img.save("outputImage.png");
    }
}

Update:

Not sure what the type of notes is, but something like this might work too. Insert the correct type for one element of Notes into the for loop where I wrote ???.

void keyPressed() {  
    if (key == 's' || key == 'S') {
        PImage img = createImage(posX, specSize, RGB);
        for(??? note : notes ){
            int x = note.getX();
            int y = note.getY();
            int loc = x + y * posX;
            img.pixels[loc] = color(note.getR(), note.getG(), note.getB());
        }
        img.updatePixels();
        img.save("outputImage.png");
    }
}

Upvotes: 1

Related Questions