Using Guava's Tables.toTable

Viewed 737

I have a List of Thing holding two atrributes : status (an Enum) and owner (another object).

I want to obtain a Guava Table<owner, status, Long> by traversing the ArrayList and counting the objects, including a count of 0 if some status isn't in the List, like that:

[owner1, status1, 2], [owner1, status2, 0], [owner2, status1, 3], [owner2, status2, 2]

how to use .collect(Tables.toTable()) in that case?

2 Answers

The below code would create a table with counts, but without zero-counts.

List<Thing> listOfThings = ...;

Table<Owner, Status, Long> table = 
    listOfThings.stream().collect(
        Tables.toTable(
            Thing::getOwner,             // Row key extractor
            Thing::getStatus,            // Column key extractor
            thing -> 1,                  // Value converter (a single value counts '1')
            (count1, count2) -> count1 + count2, // Value merger (counts add up)
            HashBasedTable::create       // Table creator
        )
    );

To add the missing cells into the table (with zero-values), you would need to additionally iterate though all the possible values (of Status and Owner), and put the 0-value if there's no value yet. Note that, if Owner isn't an enum, there's no trivial way to get all of its possible values.

Or alternatively, instead of doing this, just check for nulls when retrieving values from the table.

You need to provide mappers for the rows, columns, values, a merging function and a table supplier. So something like this:

list.stream().collect(Tables.toTable(
               Thing::getStatus,
               Thing::getOwner,
               t -> 1, //that's your counter
               (i, j) -> i + j, //that's the incrementing function
               HashBasedTable::create //a new table
            ));
Related