/* * Copyright (C) 2009 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.common.collect; import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.concurrent.Immutable; import com.google.common.annotations.GwtCompatible; /** * A {@code RegularImmutableTable} optimized for sparse data. */ @GwtCompatible @Immutable final class SparseImmutableTable extends RegularImmutableTable { private final ImmutableMap> rowMap; private final ImmutableMap> columnMap; private final int[] iterationOrderRow; private final int[] iterationOrderColumn; SparseImmutableTable(ImmutableList> cellList, ImmutableSet rowSpace, ImmutableSet columnSpace) { Map rowIndex = Maps.newHashMap(); Map> rows = Maps.newLinkedHashMap(); for (R row : rowSpace) { rowIndex.put(row, rows.size()); rows.put(row, new LinkedHashMap()); } Map> columns = Maps.newLinkedHashMap(); for (C col : columnSpace) { columns.put(col, new LinkedHashMap()); } int[] iterationOrderRow = new int[cellList.size()]; int[] iterationOrderColumn = new int[cellList.size()]; for (int i = 0; i < cellList.size(); i++) { Cell cell = cellList.get(i); R rowKey = cell.getRowKey(); C columnKey = cell.getColumnKey(); V value = cell.getValue(); iterationOrderRow[i] = rowIndex.get(rowKey); Map thisRow = rows.get(rowKey); iterationOrderColumn[i] = thisRow.size(); V oldValue = thisRow.put(columnKey, value); if (oldValue != null) { throw new IllegalArgumentException( "Duplicate value for row=" + rowKey + ", column=" + columnKey + ": " + value + ", " + oldValue); } columns.get(columnKey).put(rowKey, value); } this.iterationOrderRow = iterationOrderRow; this.iterationOrderColumn = iterationOrderColumn; ImmutableMap.Builder> rowBuilder = ImmutableMap.builder(); for (Map.Entry> row : rows.entrySet()) { rowBuilder.put(row.getKey(), ImmutableMap.copyOf(row.getValue())); } this.rowMap = rowBuilder.build(); ImmutableMap.Builder> columnBuilder = ImmutableMap.builder(); for (Map.Entry> col : columns.entrySet()) { columnBuilder.put(col.getKey(), ImmutableMap.copyOf(col.getValue())); } this.columnMap = columnBuilder.build(); } @Override public ImmutableMap> columnMap() { return columnMap; } @Override public ImmutableMap> rowMap() { return rowMap; } @Override public int size() { return iterationOrderRow.length; } @Override Cell getCell(int index) { int rowIndex = iterationOrderRow[index]; Map.Entry> rowEntry = rowMap.entrySet().asList().get(rowIndex); ImmutableMap row = (ImmutableMap) rowEntry.getValue(); int columnIndex = iterationOrderColumn[index]; Map.Entry colEntry = row.entrySet().asList().get(columnIndex); return cellOf(rowEntry.getKey(), colEntry.getKey(), colEntry.getValue()); } @Override V getValue(int index) { int rowIndex = iterationOrderRow[index]; ImmutableMap row = (ImmutableMap) rowMap.values().asList().get(rowIndex); int columnIndex = iterationOrderColumn[index]; return row.values().asList().get(columnIndex); } }