sixtytrees sixtytrees - 4 months ago 13
Java Question

Correct handling of last block of data in Java. Boolean tokens or outofbonds indexes?

I have a list of arrays containing (I)ndex, (C)ategory, (S)ubcategory, (V)alue.

I C S V

0 1 1 A

1 1 1 B

2 1 2 C

3 1 3 D

4 1 3 E

5 2 1 F

6 2 1 G

7 2 2 H

8 2 2 J

I need to process AB, then C, then DE. Then process AB+C+DE, repeat operation for 2 and so on. Finally write an output file with:

AB+C+DE
FG+HJ


Please, don't interpret
*
and
+
literaly as product and sum.

public void translate(List<String[]> raw) {

int oldCategory = 0;
int newCategory = 0;
int oldSubCategory = 0;
int newSubCategory = 0;

boolean keepWorking = true;
do {
oldCategory = newCategory;
newCategory = getNewCategory(oldCategory, raw); //get end of category. Now it returns 5, then 9.
do {
oldSubCategory = newSubCategory;
newSubCategory = getNewSubCategory(oldSubCategory, raw);
List<String> products = doFirstOperation(raw, oldCategory, newCategory, oldSubCategory, newSubCategory); //A*B, D*E, etc.

} while (newSubCategory< newCategory);
doSecondOperation(products); // compute "A*B+C+D*E" and append it to file

} while (newCategory < raw.size());
}


getNewCategory(oldCategory, raw)
returns the index of the first element in the new category or array.size() if current category is the last one.
In current setup I am routingly set newSubCategory outside of the scope of Category. This is asking for an ArrayIndexOutOfBoundsException down the road. I could use tokens
boolean isLastCategory
, do while (!isLastCategory) and return newCategory as the index of last element in a given category, but this looks bulky.

What would be a good way to organize such code?

Answer

This pattern is known in some places as "cascading report breaks". Here's one possible approach, in pseudo-code:

curCat = null
curSub = null
while rec = read()
    if (rec.cat != curCat)
        if (curCat != null)
            endCat()
        startCat()
    else if (rec.sub != curSub)
        endSub()
        startSub()
    accumulate rec
end while
if (curCat != null)
    endCat()

function startCat()
    curCat = rec.cat
    initialize cat accumulator
    startSub()

function startSub()
    curSub = rec.sub
    initialize sub accumulator

function endSub()
    finalize subcategory

function endCat()
    endSub()
    finalize category

If you don't like the null-checks as being wasteful (they only apply at the start of the file) you can use the following alternative:

rec = read()
if (!EOF)   
    startCat() 
    while rec = read()
        if (rec.cat != curCat)
            endCat()
            startCat()
        else if (rec.sub != curSub)
            endSub()
            startSub()
        accumulate rec
    end while
    endCat()

Adjust as needed for OOP-ness and encapsulation.

BTW, this goes back to the 1960s and COBOL report writing programs, but is still a neat way to conceptualize the idea of nested breaks and accumulation.