A RegularImmutableTable optimized for sparse data.
| 25 | |
| 26 | |
| 27 | @GwtCompatible |
| 28 | @Immutable |
| 29 | final class SparseImmutableTable<R, C, V> extends RegularImmutableTable<R, C, V> { |
| 30 | static final ImmutableTable<Object, Object, Object> EMPTY = new SparseImmutableTable<Object, Object, Object>(ImmutableList.<Cell<Object, Object, Object>>of(), ImmutableSet.of(), ImmutableSet.of()); |
| 31 | private final ImmutableMap<R, Map<C, V>> rowMap; |
| 32 | private final ImmutableMap<C, Map<R, V>> columnMap; |
| 33 | private final int[] iterationOrderRow; |
| 34 | private final int[] iterationOrderColumn; |
| 35 | |
| 36 | SparseImmutableTable( |
| 37 | ImmutableList<Cell<R, C, V>> cellList, |
| 38 | ImmutableSet<R> rowSpace, |
| 39 | ImmutableSet<C> columnSpace) { |
| 40 | Map<R, Integer> rowIndex = Maps.indexMap(rowSpace); |
| 41 | Map<R, Map<C, V>> rows = Maps.newLinkedHashMap(); |
| 42 | for (R row : rowSpace) { |
| 43 | rows.put(row, new LinkedHashMap<C, V>()); |
| 44 | } |
| 45 | Map<C, Map<R, V>> columns = Maps.newLinkedHashMap(); |
| 46 | for (C col : columnSpace) { |
| 47 | columns.put(col, new LinkedHashMap<R, V>()); |
| 48 | } |
| 49 | int[] iterationOrderRow = new int[cellList.size()]; |
| 50 | int[] iterationOrderColumn = new int[cellList.size()]; |
| 51 | for (int i = 0; i < cellList.size(); i++) { |
| 52 | Cell<R, C, V> cell = cellList.get(i); |
| 53 | R rowKey = cell.getRowKey(); |
| 54 | C columnKey = cell.getColumnKey(); |
| 55 | V value = cell.getValue(); |
| 56 | iterationOrderRow[i] = rowIndex.get(rowKey); |
| 57 | Map<C, V> thisRow = rows.get(rowKey); |
| 58 | iterationOrderColumn[i] = thisRow.size(); |
| 59 | V oldValue = thisRow.put(columnKey, value); |
| 60 | if (oldValue != null) { |
| 61 | throw new IllegalArgumentException("Duplicate value for row=" + rowKey + ", column=" + columnKey + ": " + value + ", " |
| 62 | + oldValue); |
| 63 | } |
| 64 | columns.get(columnKey).put(rowKey, value); |
| 65 | } |
| 66 | this.iterationOrderRow = iterationOrderRow; |
| 67 | this.iterationOrderColumn = iterationOrderColumn; |
| 68 | ImmutableMap.Builder<R, Map<C, V>> rowBuilder = new ImmutableMap.Builder<R, Map<C, V>>(rows.size()); |
| 69 | for (Map.Entry<R, Map<C, V>> row : rows.entrySet()) { |
| 70 | rowBuilder.put(row.getKey(), ImmutableMap.copyOf(row.getValue())); |
| 71 | } |
| 72 | this.rowMap = rowBuilder.build(); |
| 73 | ImmutableMap.Builder<C, Map<R, V>> columnBuilder = new ImmutableMap.Builder<C, Map<R, V>>(columns.size()); |
| 74 | for (Map.Entry<C, Map<R, V>> col : columns.entrySet()) { |
| 75 | columnBuilder.put(col.getKey(), ImmutableMap.copyOf(col.getValue())); |
| 76 | } |
| 77 | this.columnMap = columnBuilder.build(); |
| 78 | } |
| 79 | |
| 80 | @Override |
| 81 | public ImmutableMap<C, Map<R, V>> columnMap() { |
| 82 | return columnMap; |
| 83 | } |
| 84 |