Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 collector for Guava Immutable Table

Use case:
Process list of string via method which returns ImmutableTable of type {R,C,V}. For instance ImmutableTable of {Integer,String,Boolean} process(String item){...}

Collect the result i.e, merge all results and return ImmutableTable. Is there a way to achieve it?

Current implementation (as suggested by Bohemian):

How about using parallel stream ? Is there any concurrency issues in the below code? With Parallel stream i an getting "NullPointerException at index 1800" on tableBuilder.build(), but works fine with stream.

ImmutableTable<Integer, String, Boolean> buildData() {   

  // list of 4 AwsS3KeyName   
listToProcess.parallelStream() 

  //Create new instance via Guice dependency injection 
.map(s3KeyName -> ProcessorInstanceProvider.get()    
.fetchAndBuild(s3KeyName)) 
.forEach(tableBuilder::putAll); 

 return tableBuilder.build(); }

While below code worksgreat with stream as well as parallel stream. But ImmutableBuild is failing due to duplicate entry for row and col. What could be the best way to prevent duplicates while merging tables ?

public static <R, C, V> Collector<ImmutableTable<R, C, V>,     
ImmutableTable.Builder<R, C, V>, ImmutableTable<R, C, V>>   
toImmutableTable() 
{ 
return Collector.of(ImmutableTable.Builder::new, 
ImmutableTable.Builder::putAll, (builder1, builder2) -> 
builder1.putAll(builder2.build()), ImmutableTable.Builder::build); }

Edit : If there is any duplicate entry in ImmutableTable.Builder while merging different tables then it fails,

Trying to avoid faluire by putting ImmutableTables in HashBasedTable

  ImmutableTable.copyOf(itemListToProcess.parallelStream()
            .map(itemString ->
           ProcessorInstanceProvider.get()
                    .buildImmutableTable(itemString))
                    .collect(
                            Collector.of(
                                    HashBasedTable::create,
                                    HashBasedTable::putAll,
                                    (a, b) -> {
                                        a.putAll(b);
                                        return a;
                                    }));
  )

But i am getting runtime exception "Caused by: java.lang.IllegalAccessError: tried to access class com.google.common.collect.AbstractTable".

How can we use HashBasedTable as Accumulator to collect ImmutablesTables, as HashBasedTable overrides the existing entry with latest one and doesn't fail if we try to put duplicate entry , and return aggregated Immutable table.

like image 591
sidss Avatar asked Oct 21 '25 06:10

sidss


2 Answers

Since Guava 21 you can use ImmutableTable.toImmutableTable collector.

public ImmutableTable<Integer, String, Boolean> processList(List<String> strings) {
    return strings.stream()
            .map(this::processText)
            .flatMap(table -> table.cellSet().stream())
            .collect(ImmutableTable.toImmutableTable(
                    Table.Cell::getRowKey,
                    Table.Cell::getColumnKey,
                    Table.Cell::getValue,
                    (b1, b2) -> b1 && b2 // You can ommit merge function!
            ));
}

private ImmutableTable<Integer, String, Boolean> processText(String text) {
    return ImmutableTable.of(); // Whatever
}
like image 133
Václav Kužel Avatar answered Oct 23 '25 20:10

Václav Kužel


This should work:

List<String> list; // given a list of String

ImmutableTable result = list.parallelStream()
    .map(processor::process) // converts String to ImmutableTable
    .collect(ImmutableTable.Builder::new, ImmutableTable.Builder::putAll,
        (a, b) -> a.putAll(b.build())
    .build();

This reduction is threadsafe.


Or using HashBasedTable as the intermediate data structure:

ImmutableTable result = ImmutableTable.copyOf(list.parallelStream()
    .map(processor::process) // converts String to ImmutableTable
    .collect(HashBasedTable::create, HashBasedTable::putAll, HashBasedTable::putAll));
like image 44
Bohemian Avatar answered Oct 23 '25 19:10

Bohemian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!