1
\$\begingroup\$

I have a string array:

def invoices = [LEDES98BI V2,
LINE|INVOICE_DATE|INVOICE_NUMBER|INVOICE_TOTAL,
1|20150301|INV-Error_Test1|22,
2|20150301|INV-Error_Test1|24,
3|20150301|INV-Error_Test2|26,
4|20150301|INV-Error_Test2|28,]

I tried to convert it to HasMap<String, List<List>> with key as invoice numbers(INV-Error_Test1, INV-Error_Test2) and the values are each invoice line:

[
INV-Error_Test2:[[3,20150301, INV-Error_Test2,26], [4,20150301, INV-Error_Test2,28]], 
INV-Error_Test1:[[1,20150301, INV-Error_Test1,22], [2,20150301, INV-Error_Test1,24]]
]

And this is the method which converts the string array into <String, List<List>> tokens:

def extractInvoiceLineItems(def invoices) {
    Map invLineItems = new HashMap<String, ArrayList<ArrayList>>();
    def lineItems = []
    for(int i = 2; i<invoices.length; i++){
       def tokens =  invoices[i].split('\\|') as List
       if(tokens.size != 1) {
        lineItems.add(tokens)           
      }
    }

    for (int i=0; i< lineItems.size; i++) {
        invNumber = lineItems.get(i).get(1)
         if(invLineItems.keySet().find{it == invNumber}) {
            templineItem = invLineItems.get(invNumber)
            templineItem.add(lineItems.get(i))
            invLineItems.put(invNumber,templineItem)      
         }
        else {
            def list = []
            list.add(lineItems.get(i))
            invLineItems.put(invNumber,list)
        }      
    }
invLineItems
}

I am using lots of traditional for loops and am wondering whether it can be simplified further (using closures or any other way).

\$\endgroup\$
2
\$\begingroup\$

Yes, it can be simplified further. I divided the process into three steps and added comments and assertions to make it easier to see how it works.

// Simulate converting a CSV file into a list.
def csv = 
'''LEDES98BI V2
LINE|INVOICE_DATE|INVOICE_NUMBER|INVOICE_TOTAL
1|20150301|INV-Error_Test1|22
2|20150301|INV-Error_Test1|24
3|20150301|INV-Error_Test2|26
4|20150301|INV-Error_Test2|28'''.split(/\n/)

assert csv == [
    'LEDES98BI V2', 
    'LINE|INVOICE_DATE|INVOICE_NUMBER|INVOICE_TOTAL',
    '1|20150301|INV-Error_Test1|22',
    '2|20150301|INV-Error_Test1|24',
    '3|20150301|INV-Error_Test2|26',
    '4|20150301|INV-Error_Test2|28']

/* 
 * Ignore the first two csv lines and create a list of lists.
 * The inner lists represent the fields of each record.
 */
def invoices = csv[2..-1].collect { it.tokenize('|') }

assert invoices == [
    ['1', '20150301', 'INV-Error_Test1', '22'], 
    ['2', '20150301', 'INV-Error_Test1', '24'], 
    ['3', '20150301', 'INV-Error_Test2', '26'], 
    ['4', '20150301', 'INV-Error_Test2', '28']]

/*
 * Create a Map by grouping each record by its invoice number.
 */
invoices = invoices.groupBy { it[2] }

assert invoices == [
    'INV-Error_Test1':[
        ['1', '20150301', 'INV-Error_Test1', '22'],
        ['2', '20150301', 'INV-Error_Test1', '24']
    ], 
    'INV-Error_Test2':[
        ['3', '20150301', 'INV-Error_Test2', '26'],
        ['4', '20150301', 'INV-Error_Test2', '28']
    ]
]

Here's the same program in a condensed form to give you an idea of just how concisely this can be done:

'''LEDES98BI V2
LINE|INVOICE_DATE|INVOICE_NUMBER|INVOICE_TOTAL
1|20150301|INV-Error_Test1|22
2|20150301|INV-Error_Test1|24
3|20150301|INV-Error_Test2|26
4|20150301|INV-Error_Test2|28'''
    .split(/\n/)[2..-1]
    .collect { it.tokenize('|') }
    .groupBy { it[2] }
\$\endgroup\$
1
\$\begingroup\$

Extending to Emmanuel Rosa's answer, drop(2) can be used to skip headers. The advantage is that we can use Safe Navigation operator (?.) and avoid NPE in real scenarios

'''LEDES98BI V2
LINE|INVOICE_DATE|INVOICE_NUMBER|INVOICE_TOTAL
1|20150301|INV-Error_Test1|22
2|20150301|INV-Error_Test1|24
3|20150301|INV-Error_Test2|26
4|20150301|INV-Error_Test2|28'''
        .split(/\n/).drop(2)
        .collect { it.tokenize('|') }
        .groupBy { it[2] }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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