Last active
August 9, 2024 04:19
-
-
Save nithinivi/6aaeb76bb88e9f9d512f2495ef827465 to your computer and use it in GitHub Desktop.
LookupTable
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import org.jetbrains.annotations.NotNull; | |
| import java.util.Collection; | |
| import java.util.HashMap; | |
| import java.io.Serializable; | |
| import java.util.Collection; | |
| import java.util.Set; | |
| import java.util.Map; | |
| import java.util.stream.Collectors; | |
| public interface LookupTable<R, C, V> extends Serializable { | |
| /** | |
| * Returns {@code true} if the table contains a mapping with the specified row and column keys. | |
| * | |
| * @param rowKey key of row to search for | |
| * @param columnKey key of column to search for | |
| */ | |
| boolean has( | |
| R rowKey, | |
| C columnKey); | |
| /** | |
| * Returns {@code true} if the table contains a mapping with the specified value. | |
| * | |
| * @param value value to search for | |
| */ | |
| boolean containsValue(V value); | |
| V get(R rowKey, C columnKey); | |
| /** | |
| * Associates the specified value with the specified keys. If the table already contained a | |
| * mapping for those keys, the old value is replaced with the specified value. | |
| * | |
| * @param rowKey row key that the value should be associated with | |
| * @param columnKey column key that the value should be associated with | |
| * @param value value to be associated with the specified keys | |
| * @return the value previously associated with the keys, or {@code null} if no mapping existed | |
| * for the keys | |
| */ | |
| V put(R rowKey, C columnKey, V value); | |
| // | |
| // /** | |
| // * Copies all mappings from the specified table to this table. The effect is equivalent to calling | |
| // * {@link #put} with each row key / column key / value mapping in {@code table}. | |
| // * | |
| // * @param table the table to add to this table | |
| // */ | |
| // void putAll(Table<? extends R, ? extends C, ? extends V> table); | |
| /** | |
| * Removes all mappings from the table. | |
| */ | |
| V remove(R rowKey, C columnKey); | |
| /** | |
| * Returns a collection of all values, which may contain duplicates. Changes to the returned | |
| * collection will update the underlying table, and vice versa. | |
| * | |
| * @return collection of values | |
| */ | |
| Collection<V> values(); | |
| /** | |
| * Returns {@code true} if the table contains no mappings. | |
| */ | |
| boolean isEmpty(); | |
| /** | |
| * Returns the number of row key / column key / value mappings in the table. | |
| */ | |
| int size(); | |
| /** | |
| * Removes all mappings from the table. | |
| */ | |
| void clear(); | |
| /** | |
| * Returns a Set of the row keys contained in this table. | |
| * | |
| * @return A Set view of the row keys contained in this table. | |
| */ | |
| Set<R> rowKeySet(); | |
| /** | |
| * Returns a Set of the column keys contained in this table. | |
| * | |
| * @return A Set view of the column keys contained in this table. | |
| */ | |
| Set<C> columnKeySet(); | |
| } | |
| class LookupHashTable<R, C, V> implements LookupTable<R, C, V> { | |
| private final Map<R, Map<C, V>> table = new HashMap<>(); | |
| @Override | |
| public boolean has(@NotNull R rowKey, @NotNull C columnKey) { | |
| return table.containsKey(rowKey) && table.get(rowKey).containsKey(columnKey); | |
| } | |
| @Override | |
| public boolean containsValue(@NotNull V value) { | |
| return table.values().stream() | |
| .flatMap(innerMap -> innerMap.values().stream()) | |
| .anyMatch(v -> v.equals(value)); | |
| } | |
| @Override | |
| public V get(@NotNull R rowKey, @NotNull C columnKey) { | |
| return table.containsKey(rowKey) | |
| ? table.get(rowKey).get(columnKey) | |
| : null; | |
| } | |
| @Override | |
| public V put(@NotNull R rowKey, @NotNull C columnKey, @NotNull V value) { | |
| if (table.containsKey(rowKey) && table.get(rowKey) != null) { | |
| table.get(rowKey).put(columnKey, value); | |
| } else { | |
| var map = new HashMap<C, V>(); | |
| map.put(columnKey, value); | |
| table.put(rowKey, map); | |
| } | |
| return table.get(rowKey).get(columnKey); | |
| } | |
| @Override | |
| public V remove(@NotNull R rowKey, @NotNull C columnKey) { | |
| if (!table.containsKey(rowKey)) | |
| return null; | |
| if (!table.get(rowKey).containsKey(columnKey)) | |
| return null; | |
| V removed; | |
| removed = table.get(rowKey).remove(columnKey); | |
| if (table.get(rowKey).isEmpty()) | |
| table.remove(rowKey); | |
| return removed; | |
| } | |
| @Override | |
| public Collection<V> values() { | |
| return table.values().stream() | |
| .flatMap(map -> map.values().stream()) | |
| .collect(Collectors.toList()); | |
| } | |
| @Override | |
| public boolean isEmpty() { | |
| return table.isEmpty(); | |
| } | |
| @Override | |
| public int size() { | |
| return table.values().stream() | |
| .map(Map::size) | |
| .reduce(0, Integer::sum); | |
| } | |
| @Override | |
| public void clear() { | |
| table.clear(); | |
| } | |
| @Override | |
| public Set<R> rowKeySet() { | |
| return table.keySet(); | |
| } | |
| @Override | |
| public Set<C> columnKeySet() { | |
| return table.values() | |
| .stream().flatMap(map -> map.keySet().stream()) | |
| .collect(Collectors.toSet()); | |
| } | |
| } | |
| public class ConcurrentLookupTable<R, C, V> implements LookupTable<R, C, V> { | |
| private final Map<R, Map<C, V>> table = new ConcurrentHashMap<>(); | |
| @Override | |
| public boolean has(@NotNull R rowKey, @NotNull C columnKey) { | |
| return table.containsKey(rowKey) && table.get(rowKey).containsKey(columnKey); | |
| } | |
| @Override | |
| public boolean containsValue(@NotNull V value) { | |
| return table.values().stream() | |
| .flatMap(innerMap -> innerMap.values().stream()) | |
| .anyMatch(v -> v.equals(value)); | |
| } | |
| @Override | |
| public V get(@NotNull R rowKey, @NotNull C columnKey) { | |
| return table.containsKey(rowKey) | |
| ? table.get(rowKey).get(columnKey) | |
| : null; | |
| } | |
| @Override | |
| public V put(@NotNull R rowKey, @NotNull C columnKey, @NotNull V value) { | |
| if (table.containsKey(rowKey) && table.get(rowKey) != null) { | |
| synchronized (table) { | |
| table.get(rowKey).put(columnKey, value); | |
| } | |
| } else { | |
| var map = new ConcurrentHashMap<C, V>(); | |
| map.put(columnKey, value); | |
| synchronized (table) { | |
| table.put(rowKey, map); | |
| } | |
| } | |
| return table.get(rowKey).get(columnKey); | |
| } | |
| @Override | |
| public V remove(@NotNull R rowKey,@NotNull C columnKey) { | |
| if (!table.containsKey(rowKey)) | |
| return null; | |
| if (!table.get(rowKey).containsKey(columnKey)) | |
| return null; | |
| V removed; | |
| synchronized (table) { | |
| removed = table.get(rowKey).remove(columnKey); | |
| if (table.get(rowKey).isEmpty()) | |
| table.remove(rowKey); | |
| } | |
| return removed; | |
| } | |
| @Override | |
| public Collection<V> values() { | |
| return table.values().stream() | |
| .flatMap(map -> map.values().stream()) | |
| .collect(Collectors.toList()); | |
| } | |
| @Override | |
| public boolean isEmpty() { | |
| return table.isEmpty(); | |
| } | |
| @Override | |
| public int size() { | |
| return table.values().stream() | |
| .map(Map::size) | |
| .reduce(0, Integer::sum); | |
| } | |
| @Override | |
| public void clear() { | |
| table.clear(); | |
| } | |
| @Override | |
| public Set<R> rowKeySet() { | |
| return table.keySet(); | |
| } | |
| @Override | |
| public Set<C> columnKeySet() { | |
| return table.values() | |
| .stream().flatMap(map -> map.keySet().stream()) | |
| .collect(Collectors.toSet()); | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment