Get the top 3 elements from the memory cache - java

When I need to get the top 3 items from a Map, I can write the code,
private static Map<String, Integer> SortMapBasedOnValues(Map<String, Integer> map, int n) {
Map<String, Integer> sortedDecreasingly = map.entrySet().stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).limit(n)
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2, LinkedHashMap::new));
return sortedDecreasingly;
}
I have a memory cache that I use to keep track of some app data,
public class MemoryCache<K, T> {
private long timeToLive;
private LRUMap map;
protected class CacheObject {
public long lastAccessed = System.currentTimeMillis();
public T value;
protected CacheObject(T value) {
this.value = value;
}
}
public MemoryCache(long timeToLive, final long timerInterval, int maxItems) {
this.timeToLive = timeToLive * 1000;
map = new LRUMap(maxItems);
if (this.timeToLive > 0 && timerInterval > 0) {
Thread t = new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(timerInterval * 1000);
} catch (InterruptedException ex) {
}
cleanup();
}
}
});
t.setDaemon(true);
t.start();
}
}
public void put(K key, T value) {
synchronized (map) {
map.put(key, new CacheObject(value));
}
}
#SuppressWarnings("unchecked")
public T get(K key) {
synchronized (map) {
CacheObject c = (CacheObject) map.get(key);
if (c == null)
return null;
else {
c.lastAccessed = System.currentTimeMillis();
return c.value;
}
}
}
public void remove(K key) {
synchronized (map) {
map.remove(key);
}
}
public int size() {
synchronized (map) {
return map.size();
}
}
#SuppressWarnings("unchecked")
public void cleanup() {
long now = System.currentTimeMillis();
ArrayList<K> deleteKey = null;
synchronized (map) {
MapIterator itr = map.mapIterator();
deleteKey = new ArrayList<K>((map.size() / 2) + 1);
K key = null;
CacheObject c = null;
while (itr.hasNext()) {
key = (K) itr.next();
c = (CacheObject) itr.getValue();
if (c != null && (now > (timeToLive + c.lastAccessed))) {
deleteKey.add(key);
}
}
}
for (K key : deleteKey) {
synchronized (map) {
map.remove(key);
}
Thread.yield();
}
}
}
Inside the app, I initialize it,
MemoryCache<String, Integer> cache = new MemoryCache<String, Integer>(200, 500, 100);
Then I can add the data,
cache.put("productId", 500);
I would like to add functionality in the MemoryCache class so if called will return a HashMap of the top 3 items based on the value.
Do you have any advise how to implement that?

While I don't have a good answer, I convert the MemoryCache to the HashMap with an additional functionality implemented inside the class of MemoryCache and later, use it with the function provided earlier to retrieve the top 3 items based on the value,
Here is my updated code,
/**
* convert the cache full of items to regular HashMap with the same
* key and value pair
*
* #return
*/
public Map<Product, Integer> convertToMap() {
synchronized (lruMap) {
Map<Product, Integer> convertedMap = new HashMap<>();
MapIterator iterator = lruMap.mapIterator();
K k = null;
V v = null;
CacheObject o = null;
while (iterator.hasNext()) {
k = (K) iterator.next();
v = (V) iterator.getValue();
Product product = (Product) k;
o = (CacheObject) v;
int itemsSold = Integer.valueOf((o.value).toString());
convertedMap.put(product, itemsSold);
}
return convertedMap;
}
}

Related

How to retrieve tables which exists in a pdf using AWS Textract in java

I found article below to do in python.
https://docs.aws.amazon.com/textract/latest/dg/examples-export-table-csv.html
also I used article below to extract text.
https://docs.aws.amazon.com/textract/latest/dg/detecting-document-text.html
but above article helped to get only text, I also used function "block.getBlockType()"
of Block but none of block returned its type as "CELL" even tables are there in image/pdf.
Help me found java library similar to "boto3" to extract all tables.
What I did, I created models of each dataset in the json response and can use this models to build a table view in jsf.
public static List<TableModel> getTablesFromTextract(TextractModel textractModel) {
List<TableModel> tables = null;
try {
if (textractModel != null) {
tables = new ArrayList<>();
List<BlockModel> tableBlocks = new ArrayList<>();
Map<String, BlockModel> blockMap = new HashMap<>();
for (BlockModel block : textractModel.getBlocks()) {
if (block.getBlockType().equals("TABLE")) {
tableBlocks.add(block);
}
blockMap.put(block.getId(), block);
}
for (BlockModel blockModel : tableBlocks) {
Map<Long, Map<Long, String>> rowMap = new HashMap<>();
for (RelationshipModel relationship : blockModel.getRelationships()) {
if (relationship.getType().equals("CHILD")) {
for (String id : relationship.getIds()) {
BlockModel cell = blockMap.get(id);
if (cell.getBlockType().equals("CELL")) {
long rowIndex = cell.getRowIndex();
long columnIndex = cell.getColumnIndex();
if (!rowMap.containsKey(rowIndex)) {
rowMap.put(rowIndex, new HashMap<>());
}
Map<Long, String> columnMap = rowMap.get(rowIndex);
columnMap.put(columnIndex, getCellText(cell, blockMap));
}
}
}
}
tables.add(new TableModel(blockModel, rowMap));
}
System.out.println("row Map " + tables.toString());
}
} catch (Exception e) {
LOG.error("Could not get table from textract model", e);
}
return tables;
}
private static String getCellText(BlockModel cell, Map<String, BlockModel> blockMap) {
String text = "";
try {
if (cell != null
&& CollectionUtils.isNotEmpty(cell.getRelationships())) {
for (RelationshipModel relationship : cell.getRelationships()) {
if (relationship.getType().equals("CHILD")) {
for (String id : relationship.getIds()) {
BlockModel word = blockMap.get(id);
if (word.getBlockType().equals("WORD")) {
text += word.getText() + " ";
} else if (word.getBlockType().equals("SELECTION_ELEMENT")) {
if (word.getSelectionStatus().equals("SELECTED")) {
text += "X ";
}
}
}
}
}
}
} catch (Exception e) {
LOG.error("Could not get cell text of table", e);
}
return text;
}
TableModel to create the view from:
public class TableModel {
private BlockModel table;
private Map<Long, Map<Long, String>> rowMap;
public TableModel(BlockModel table, Map<Long, Map<Long, String>> rowMap) {
this.table = table;
this.rowMap = rowMap;
}
public BlockModel getTable() {
return table;
}
public void setTable(BlockModel table) {
this.table = table;
}
public Map<Long, Map<Long, String>> getRowMap() {
return rowMap;
}
public void setRowMap(Map<Long, Map<Long, String>> rowMap) {
this.rowMap = rowMap;
}
#Override
public String toString() {
return table.getId() + " - " + rowMap.toString();
}
I have something similar:
public class AnalyzeDocument {
public DocumentModel startProcess(byte[] content) {
Region region = Region.EU_WEST_2;
TextractClient textractClient = TextractClient.builder().region(region)
.credentialsProvider(EnvironmentVariableCredentialsProvider.create()).build();
return analyzeDoc(textractClient, content);
}
public DocumentModel analyzeDoc(TextractClient textractClient, byte[] content) {
try {
SdkBytes sourceBytes = SdkBytes.fromByteArray(content);
Util util = new Util();
Document myDoc = Document.builder().bytes(sourceBytes).build();
List<FeatureType> featureTypes = new ArrayList<FeatureType>();
featureTypes.add(FeatureType.FORMS);
featureTypes.add(FeatureType.TABLES);
AnalyzeDocumentRequest analyzeDocumentRequest = AnalyzeDocumentRequest.builder().featureTypes(featureTypes)
.document(myDoc).build();
AnalyzeDocumentResponse analyzeDocument = textractClient.analyzeDocument(analyzeDocumentRequest);
List<Block> docInfo = analyzeDocument.blocks();
// util.displayBlockInfo(docInfo);
PageModel pageModel = util.getTableResults(docInfo);
DocumentModel documentModel = new DocumentModel();
documentModel.getPages().add(pageModel);
Iterator<Block> blockIterator = docInfo.iterator();
while (blockIterator.hasNext()) {
Block block = blockIterator.next();
log.debug("The block type is " + block.blockType().toString());
}
return documentModel;
} catch (TextractException e) {
System.err.println(e.getMessage());
}
return null;
}
and this is the util file:
public PageModel getTableResults(List<Block> blocks) {
List<Block> tableBlocks = new ArrayList<>();
Map<String, Block> blockMap = new HashMap<>();
for (Block block : blocks) {
blockMap.put(block.id(), block);
if (block.blockType().equals(BlockType.TABLE)) {
tableBlocks.add(block);
log.debug("added table: " + block.text());
}
}
PageModel page = new PageModel();
if (tableBlocks.size() == 0) {
return null;
}
int i = 0;
for (Block table : tableBlocks) {
page.getTables().add(generateTable(table, blockMap, i++));
}
return page;
}
private TableModel generateTable(Block table, Map<String, Block> blockMap, int index) {
TableModel model = new TableModel();
Map<Integer, Map<Integer, String>> rows = getRowsColumnsMap(table, blockMap);
model.setTableId("Table_" + index);
for (Map.Entry<Integer, Map<Integer, String>> entry : rows.entrySet()) {
RowModel rowModel = new RowModel();
Map<Integer, String> value = entry.getValue();
for (int i = 0; i < value.size(); i++) {
rowModel.getCells().add(value.get(i));
}
model.getRows().add(rowModel);
}
return model;
}
private Map<Integer, Map<Integer, String>> getRowsColumnsMap(Block block, Map<String, Block> blockMap) {
Map<Integer, Map<Integer, String>> rows = new HashMap<>();
for (Relationship relationship : block.relationships()) {
if (relationship.type().equals(RelationshipType.CHILD)) {
for (String childId : relationship.ids()) {
Block cell = blockMap.get(childId);
if (cell != null) {
int rowIndex = cell.rowIndex();
int colIndex = cell.columnIndex();
if (rows.get(rowIndex) == null) {
Map<Integer, String> row = new HashMap<>();
rows.put(rowIndex, row);
}
rows.get(rowIndex).put(colIndex, getText(cell, blockMap));
}
}
}
}
return rows;
}
public String getText(Block block, Map<String, Block> blockMap) {
String text = "";
if (block.relationships() != null && block.relationships().size() > 0) {
for (Relationship relationship : block.relationships()) {
if (relationship.type().equals(RelationshipType.CHILD)) {
for (String childId : relationship.ids()) {
Block wordBlock = blockMap.get(childId);
if (wordBlock != null && wordBlock.blockType() != null) {
if (wordBlock.blockType().equals(BlockType.WORD))) {
text += wordBlock.text() + " ";
}
}
}
}
}
}
return text;
}

Modifying Dijkstra to save paths with equal values - StackOverflow error

I'm trying to modify Dijkstra's algorithm to show all the paths that have the minimum value. So I decided to use a list of previous vertices. And I added an if clause that checks if the path is igual to the previous with minimum value I add the previous vertex as the parent of the current one.
The problem is that I am getting a StackOverflow error and I don't know what is causing it.
This is my code:
The purpose of the code below is to calculate Dijkstra for all of the vertices in the graph, calculate the number of times a vertex appears in the minimum paths found and display in decrescent order the all of them.
public class Dijkstra {
public static final Map<String, Integer> ordem = new HashMap<>();
public static void main(String[] args) throws FileNotFoundException, IOException {
List<Graph.Edge> edges = new ArrayList<>();
try {
FileReader arq = new FileReader("input.txt");
BufferedReader fw = new BufferedReader(arq);
String linha = "";
while (fw.ready()) {
linha = fw.readLine();
if (!linha.equals("0,0,0")) {
String parts[] = linha.split(",");
ordem.put(parts[0], 0);
ordem.put(parts[1], 0);
Graph.Edge a = new Graph.Edge(parts[0], parts[1], 100 - Integer.parseInt(parts[2]));
edges.add(a);
} else {
break;
}
}
fw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Graph g = new Graph(edges);
for (int i = 0; i < 5; i++) {
g.dijkstra(String.valueOf(i));
g.printAllPaths();
}
Object[] a = ordem.entrySet().toArray();
Arrays.sort(a, new Comparator() {
public int compare(Object o1, Object o2) {
return ((Map.Entry<String, Integer>) o2).getValue()
.compareTo(((Map.Entry<String, Integer>) o1).getValue());
}
});
for (Object e : a) {
System.out.print(((Map.Entry<String, Integer>) e).getKey() + " ");
}
System.out.println("\n");
}
}
class Graph {
private final Map<String, Vertex> graph;
public static class Edge {
public final String v1, v2;
public final int dist;
public Edge(String v1, String v2, int dist) {
this.v1 = v1;
this.v2 = v2;
this.dist = dist;
}
}
public static class Vertex implements Comparable<Vertex> {
public final String name;
public int dist = Integer.MAX_VALUE;
public List<Vertex> previous = new ArrayList<>();
public final Map<Vertex, Integer> neighbours = new HashMap<>();
public Vertex(String name) {
this.name = name;
}
private void printPath() {
if (this == this.previous) {
} else if (this.previous == null) {
} else {
//This is where I am getting the error
for (int i = 0; i<this.previous.size(); i++){
this.previous.get(i).printPath();
Dijkstra.ordem.replace(this.name, Dijkstra.ordem.get(this.name) + 1);
}
}
}
public int compareTo(Vertex other) {
if (dist == other.dist) {
return name.compareTo(other.name);
}
return Integer.compare(dist, other.dist);
}
#Override
public String toString() {
return "(" + name + ", " + dist + ")";
}
}
public Graph(List<Graph.Edge> edges) {
graph = new HashMap<>(edges.size());
for (Edge e : edges) {
if (!graph.containsKey(e.v1)) {
graph.put(e.v1, new Vertex(e.v1));
}
if (!graph.containsKey(e.v2)) {
graph.put(e.v2, new Vertex(e.v2));
}
}
for (Edge e : edges) {
graph.get(e.v1).neighbours.put(graph.get(e.v2), e.dist);
graph.get(e.v2).neighbours.put(graph.get(e.v1), e.dist);
}
}
public void dijkstra(String startName) {
if (!graph.containsKey(startName)) {
System.err.printf("Graph doesn't contain start vertex \"%s\"\n", startName);
return;
}
final Vertex source = graph.get(startName);
NavigableSet<Vertex> q = new TreeSet<>();
// Inicializacao dos vertices
for (Vertex v : graph.values()) {
//v.previous = v == source ? list : null;
if (v == source) {
v.previous.add(source);
} else {
v.previous = new ArrayList<>();
}
v.dist = v == source ? 0 : Integer.MAX_VALUE;
q.add(v);
}
dijkstra(q);
}
private void dijkstra(final NavigableSet<Vertex> q) {
Vertex u, v;
while (!q.isEmpty()) {
u = q.pollFirst();
if (u.dist == Integer.MAX_VALUE) {
}
for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) {
v = a.getKey();
final int alternateDist = u.dist + a.getValue();
if (alternateDist < v.dist) {
q.remove(v);
v.dist = alternateDist;
v.previous.add(u);
q.add(v);
} else if(alternateDist == v.dist) {
v.previous.add(u);
}
}
}
}
public void printPath(String endName) {
if (!graph.containsKey(endName)) {
System.err.printf("Graph doesn't contain end vertex \"%s\"\n", endName);
return;
}
graph.get(endName).printPath();
//System.out.println();
}
public void printAllPaths() {
for (Vertex v : graph.values()) {
v.printPath();
}
}
}
This is the error:
Exception in thread "main" java.lang.StackOverflowError
at Graph$Vertex.printPath(Dijkstra.java:117)
at Graph$Vertex.printPath(Dijkstra.java:118)
As the Error message already suggests: Your dijkstra isn't the problem.
The problem is printPath() calling itself.
Likely the culprit is
if (this == this.previous) {} ...
You compare Vertex this to List<Vertex> previous. Maybe you want to check
if (this == this.previous.get(this.previous.size() - 1)) {} ...
instead.
I didn't test this, because your code is (1.) too long and (2.) not self-contained (missing at least "input.txt").

How to group inside Flink with my model

Im using Flink with Java to make my recommendation system using our logic.
So i have a dataset:
[user] [item]
100 1
100 2
100 3
100 4
100 5
200 1
200 2
200 3
200 6
300 1
300 6
400 7
So i map all to a tuple :
DataSet<Tuple3<Long, Long, Integer>> csv = text.flatMap(new LineSplitter()).groupBy(0, 1).reduceGroup(new GroupReduceFunction<Tuple2<Long, Long>, Tuple3<Long, Long, Integer>>() {
#Override
public void reduce(Iterable<Tuple2<Long, Long>> iterable, Collector<Tuple3<Long, Long, Integer>> collector) throws Exception {
Long customerId = 0L;
Long itemId = 0L;
Integer count = 0;
for (Tuple2<Long, Long> item : iterable) {
customerId = item.f0;
itemId = item.f1;
count = count + 1;
}
collector.collect(new Tuple3<>(customerId, itemId, count));
}
});
After i get all Customers and is Items inside arraylist:
DataSet<CustomerItems> customerItems = csv.groupBy(0).reduceGroup(new GroupReduceFunction<Tuple3<Long, Long, Integer>, CustomerItems>() {
#Override
public void reduce(Iterable<Tuple3<Long, Long, Integer>> iterable, Collector<CustomerItems> collector) throws Exception {
ArrayList<Long> newItems = new ArrayList<>();
Long customerId = 0L;
for (Tuple3<Long, Long, Integer> item : iterable) {
customerId = item.f0;
newItems.add(item.f1);
}
collector.collect(new CustomerItems(customerId, newItems));
}
});
Now i need get all "similar" customers. But after try a lot of things, nothing work.
The logic will be:
for ci : CustomerItems
c1 = c1.customerId
for ci2 : CustomerItems
c2 = ci2.cstomerId
if c1 != c2
if c2.getItems() have any item inside c1.getItems()
collector.collect(new Tuple2<c1, c2>)
I tried it using reduce, but i cant iterate on iterator two time (loop inside loop).
Can anyone help me?
You can cross the dataset with itself and basically insert your logic 1:1 into a cross function (excluding the 2 loops since the cross does that for you).
I solve the problem, but i need group and reduce after the "cross". I dont know that it is the best method. Can anyone suggest something?
The result is here:
package org.myorg.quickstart;
import org.apache.flink.api.common.functions.CrossFunction;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.functions.GroupReduceFunction;
import org.apache.flink.api.java.DataSet;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.util.Collector;
import java.io.Serializable;
import java.util.ArrayList;
public class UserRecommendation {
public static void main(String[] args) throws Exception {
final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
// le o arquivo cm o dataset
DataSet<String> text = env.readTextFile("/Users/paulo/Downloads/dataset.csv");
// cria tuple com: customer | item | count
DataSet<Tuple3<Long, Long, Integer>> csv = text.flatMap(new LineFieldSplitter()).groupBy(0, 1).reduceGroup(new GroupReduceFunction<Tuple2<Long, Long>, Tuple3<Long, Long, Integer>>() {
#Override
public void reduce(Iterable<Tuple2<Long, Long>> iterable, Collector<Tuple3<Long, Long, Integer>> collector) throws Exception {
Long customerId = 0L;
Long itemId = 0L;
Integer count = 0;
for (Tuple2<Long, Long> item : iterable) {
customerId = item.f0;
itemId = item.f1;
count = count + 1;
}
collector.collect(new Tuple3<>(customerId, itemId, count));
}
});
// agrupa os items do customer dentro do customer
final DataSet<CustomerItems> customerItems = csv.groupBy(0).reduceGroup(new GroupReduceFunction<Tuple3<Long, Long, Integer>, CustomerItems>() {
#Override
public void reduce(Iterable<Tuple3<Long, Long, Integer>> iterable, Collector<CustomerItems> collector) throws Exception {
ArrayList<Long> newItems = new ArrayList<>();
Long customerId = 0L;
for (Tuple3<Long, Long, Integer> item : iterable) {
customerId = item.f0;
newItems.add(item.f1);
}
collector.collect(new CustomerItems(customerId, newItems));
}
});
// obtém todos os itens do customer que pertence a um usuário parecido
DataSet<CustomerItems> ci = customerItems.cross(customerItems).with(new CrossFunction<CustomerItems, CustomerItems, CustomerItems>() {
#Override
public CustomerItems cross(CustomerItems customerItems, CustomerItems customerItems2) throws Exception {
if (!customerItems.customerId.equals(customerItems2.customerId)) {
boolean has = false;
for (Long item : customerItems2.items) {
if (customerItems.items.contains(item)) {
has = true;
break;
}
}
if (has) {
for (Long item : customerItems2.items) {
if (!customerItems.items.contains(item)) {
customerItems.ritems.add(item);
}
}
}
}
return customerItems;
}
}).groupBy(new KeySelector<CustomerItems, Long>() {
#Override
public Long getKey(CustomerItems customerItems) throws Exception {
return customerItems.customerId;
}
}).reduceGroup(new GroupReduceFunction<CustomerItems, CustomerItems>() {
#Override
public void reduce(Iterable<CustomerItems> iterable, Collector<CustomerItems> collector) throws Exception {
CustomerItems c = new CustomerItems();
for (CustomerItems current : iterable) {
c.customerId = current.customerId;
for (Long item : current.ritems) {
if (!c.ritems.contains(item)) {
c.ritems.add(item);
}
}
}
collector.collect(c);
}
});
ci.first(100).print();
System.out.println(ci.count());
}
public static class CustomerItems implements Serializable {
public Long customerId;
public ArrayList<Long> items = new ArrayList<>();
public ArrayList<Long> ritems = new ArrayList<>();
public CustomerItems() {
}
public CustomerItems(Long customerId, ArrayList<Long> items) {
this.customerId = customerId;
this.items = items;
}
#Override
public String toString() {
StringBuilder itemsData = new StringBuilder();
if (items != null) {
for (Long item : items) {
if (itemsData.length() == 0) {
itemsData.append(item);
} else {
itemsData.append(", ").append(item);
}
}
}
StringBuilder ritemsData = new StringBuilder();
if (ritems != null) {
for (Long item : ritems) {
if (ritemsData.length() == 0) {
ritemsData.append(item);
} else {
ritemsData.append(", ").append(item);
}
}
}
return String.format("[ID: %d, Items: %s, RItems: %s]", customerId, itemsData, ritemsData);
}
}
public static final class LineFieldSplitter implements FlatMapFunction<String, Tuple2<Long, Long>> {
#Override
public void flatMap(String value, Collector<Tuple2<Long, Long>> out) {
// normalize and split the line
String[] tokens = value.split("\t");
if (tokens.length > 1) {
out.collect(new Tuple2<>(Long.valueOf(tokens[0]), Long.valueOf(tokens[1])));
}
}
}
}
Link with gist:
https://gist.github.com/prsolucoes/b406ae98ea24120436954967e37103f6

MultiKey HashMap Implementation

I'm looking for an implementation of MultiKey (actually DoubleDouble) to single Value. * BUT * you can access the value via ONE OF THE KEYS!
meaning, It's not mandatory to have both keys in order to access the map.
I know I can write something to fulfill my request - but the question is if there is something out there that is already written so I can use it out-of-the-box.
Thanks :-)
EDIT:
At this point the best implementation I can think of is this:
class DoubleKeyHashMap<K1, K2, V> {
BiMap<K1, K2> keys; // Bidirectional map
Map<K2, V> values;
..
..
}
This seems like a good start to a multi key map implementation.
Edited to add a removeElement method, and to save and return a List of values.
package com.ggl.testing;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class MultiMap<K, V> {
private static long sequence = 0;
private Map<K, Long> key1Map;
private Map<K, Long> key2Map;
private Map<Long, List<V>> valueMap;
public MultiMap() {
this.key1Map = new HashMap<>();
this.key2Map = new HashMap<>();
this.valueMap = new HashMap<>();
}
public void addElement(K key1, K key2, V value) {
boolean key1boolean = key1Map.containsKey(key1);
boolean key2boolean = key2Map.containsKey(key2);
boolean key3boolean = key1Map.containsKey(key2);
boolean key4boolean = key2Map.containsKey(key1);
if (key1boolean && key2boolean) {
Long key1Value = key1Map.get(key1);
Long key2Value = key2Map.get(key2);
updateValue(key1, key2, key1Value, key2Value, value);
} else if (key3boolean && key4boolean) {
Long key1Value = key1Map.get(key2);
Long key2Value = key2Map.get(key1);
updateValue(key1, key2, key1Value, key2Value, value);
} else if (key1boolean || key4boolean) {
String s = displayDuplicateError(key1);
throw new IllegalStateException(s);
} else if (key2boolean || key3boolean) {
String s = displayDuplicateError(key2);
throw new IllegalStateException(s);
} else {
createValue(key1, key2, value);
}
}
private void createValue(K key1, K key2, V value) {
Long newKeyValue = sequence++;
key1Map.put(key1, newKeyValue);
key2Map.put(key2, newKeyValue);
List<V> values = new ArrayList<>();
values.add(value);
valueMap.put(newKeyValue, values);
}
private void updateValue(K key1, K key2, Long key1Value, Long key2Value,
V value) {
if (key1Value.equals(key2Value)) {
List<V> values = valueMap.get(key1Value);
values.add(value);
valueMap.put(key1Value, values);
} else {
String s = displayMismatchError(key1, key2);
throw new IllegalStateException(s);
}
}
private String displayMismatchError(K key1, K key2) {
return "Keys " + key1.toString() + " & " + key2.toString()
+ " have a different internal key.";
}
private String displayDuplicateError(K key) {
return "Key " + key.toString() + " is part of another key pair";
}
public List<V> getElement(K key) {
if (key1Map.containsKey(key)) {
return valueMap.get(key1Map.get(key));
}
if (key2Map.containsKey(key)) {
return valueMap.get(key2Map.get(key));
}
return null;
}
public boolean removeElement(K key) {
if (key1Map.containsKey(key)) {
Long key1Value = key1Map.get(key);
Set<Entry<K, Long>> entrySet = key2Map.entrySet();
K key2 = getOtherKey(key1Value, entrySet);
valueMap.remove(key1Value);
key1Map.remove(key);
key2Map.remove(key2);
return true;
} else if (key2Map.containsKey(key)) {
Long key2Value = key2Map.get(key);
Set<Entry<K, Long>> entrySet = key1Map.entrySet();
K key1 = getOtherKey(key2Value, entrySet);
valueMap.remove(key2Value);
key1Map.remove(key1);
key2Map.remove(key);
return true;
}
return false;
}
private K getOtherKey(Long key1Value, Set<Entry<K, Long>> entrySet) {
Iterator<Entry<K, Long>> iter = entrySet.iterator();
K key = null;
while (iter.hasNext() && key == null) {
Entry<K, Long> entry = iter.next();
if (entry.getValue().equals(key1Value)) {
key = entry.getKey();
}
}
return key;
}
public static void main(String[] args) {
MultiMap<String, String> multiMap = new MultiMap<>();
try {
multiMap.addElement("one", "two", "numbers");
multiMap.addElement("alpha", "beta", "greek alphabet");
multiMap.addElement("beta", "alpha", "alphabet");
multiMap.addElement("iron", "oxygen", "elements");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Arrays.toString(multiMap.getElement("iron")
.toArray()));
System.out.println(Arrays.toString(multiMap.getElement("beta")
.toArray()));
System.out.println(multiMap.removeElement("two"));
}
}

3 dimensional ConcurrentSkipListMap map

I have written 3 dimensional ConcurrentSkipListMap, but not able to figure out a way to iterate over it. How do i define a iterator for the same.
import java.util.concurrent.ConcurrentSkipListMap;
/**
* Helper implementation to handle 3 dimensional sorted maps
*/
public class MyCustomIndex {
private ConcurrentSkipListMap<byte[], ConcurrentSkipListMap<byte[], ConcurrentSkipListMap<byte[], byte[]>>> table;
public MyCustomIndex() {
this.table = new ConcurrentSkipListMap<byte[], ConcurrentSkipListMap<byte[], ConcurrentSkipListMap<byte[], byte[]>>>(new CustomComparator);
}
/**
*
* #param K
* #param F
* #param Q
*/
public void put(byte[] K, byte[] F, byte[] Q) {
ConcurrentSkipListMap<byte[], byte[]> QToDummyValueMap;
ConcurrentSkipListMap<byte[], ConcurrentSkipListMap<byte[], byte[]>> FToQMap;
if( table.containsK(K)) {
FToQMap = table.get(K);
if ( FToQMap.containsK(F)) {
QToDummyValueMap = FToQMap.get(F);
} else {
QToDummyValueMap = new ConcurrentSkipListMap<byte[], byte[]>(new CustomComparator);
}
} else {
QToDummyValueMap = new ConcurrentSkipListMap<byte[], byte[]>(new CustomComparator);
FToQMap = new ConcurrentSkipListMap<byte[], ConcurrentSkipListMap<byte[], byte[]>>(new CustomComparator);
}
QToDummyValueMap.put(Q, new byte[0]);
FToQMap.put(F, QToDummyValueMap);
table.put(K, FToQMap);
}
public ConcurrentSkipListMap<byte[], ConcurrentSkipListMap<byte[], ConcurrentSkipListMap<byte[], byte[]>>> gettable() {
return table;
}
public void settable(
ConcurrentSkipListMap<byte[], ConcurrentSkipListMap<byte[], ConcurrentSkipListMap<byte[], byte[]>>> table) {
this.table = table;
}
}
Here's a nested iterator that will take an Iterator<Iterator<T>> and turn it into an Iterator<T>. Also there are static methods that allow you to grow Iterator<V> objects out of Map<K,V>s along with some higher-order stuff (Iterator<Iterator<V>> and Map<K,Map<K,V> etc.).
The idea for iterating over higher levels of iterator such as Iterator<Iterator<Iterator<T>>> would be to wrap one of these inside the other as you can see in the three-way test and the MapMapMap test.
public class NestedIterator<T> implements Iterator<T> {
// Outer iterator. Goes null when exhausted.
Iterator<Iterator<T>> i2 = null;
// Inner iterator. Goes null when exhausted.
Iterator<T> i1 = null;
// Next value.
T next = null;
// Takes a depth-2 iterator.
public NestedIterator(Iterator<Iterator<T>> i2) {
this.i2 = i2;
// Prime the pump.
if (i2 != null && i2.hasNext()) {
i1 = i2.next();
}
}
#Override
public boolean hasNext() {
// Is there one waiting?
if (next == null) {
// No!
// i1 will go null if it is exhausted.
if (i1 == null) {
// i1 is exhausted! Get a new one from i2.
if (i2 != null && i2.hasNext()) {
/// Get next.
i1 = i2.next();
// Set i2 null if exhausted.
if (!i2.hasNext()) {
// Exhausted.
i2 = null;
}
} else {
// Exhausted.
i2 = null;
}
}
// A null i1 now will mean all is over!
if (i1 != null) {
if (i1.hasNext()) {
// get next.
next = i1.next();
// Set i1 null if exhausted.
if (!i1.hasNext()) {
// Exhausted.
i1 = null;
}
} else {
// Exhausted.
i1 = null;
}
}
}
return next != null;
}
#Override
public T next() {
T n = next;
next = null;
return n;
}
#Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
// Iterating across Maps of Maps of Maps.
static <K1, K2, K3, V> Iterator<Iterator<Iterator<V>>> iiiV(Map<K1, Map<K2, Map<K3, V>>> i) {
final Iterator<Map<K2, Map<K3, V>>> iV = iV(i);
return new Iterator<Iterator<Iterator<V>>>() {
#Override
public boolean hasNext() {
return iV.hasNext();
}
#Override
public Iterator<Iterator<V>> next() {
return iiV(iV.next());
}
#Override
public void remove() {
iV.remove();
}
};
}
// Iterating across Maps of Maps.
static <K1, K2, V> Iterator<Iterator<V>> iiV(Map<K1, Map<K2, V>> i) {
final Iterator<Map<K2, V>> iV = iV(i);
return new Iterator<Iterator<V>>() {
#Override
public boolean hasNext() {
return iV.hasNext();
}
#Override
public Iterator<V> next() {
return iV(iV.next());
}
#Override
public void remove() {
iV.remove();
}
};
}
// Iterating across Map values.
static <K, V> Iterator<V> iV(final Map<K, V> map) {
return iV(map.entrySet().iterator());
}
// Iterating across Map.Entry Iterators.
static <K, V> Iterator<V> iV(final Iterator<Map.Entry<K, V>> i) {
return new Iterator<V>() {
#Override
public boolean hasNext() {
return i.hasNext();
}
#Override
public V next() {
return i.next().getValue();
}
#Override
public void remove() {
i.remove();
}
};
}
// **** TESTING ****
enum I {
I1, I2, I3;
};
public static void main(String[] args) {
// Two way test.
testTwoWay();
System.out.flush();
System.err.flush();
// Three way test.
testThreeWay();
System.out.flush();
System.err.flush();
// MapMap test
testMapMap();
System.out.flush();
System.err.flush();
// MapMapMap test
testMapMapMap();
System.out.flush();
System.err.flush();
}
private static void testMapMap() {
Map<String,String> m = new TreeMap<> ();
m.put("M-1", "V-1");
m.put("M-2", "V-2");
Map<String,Map<String,String>> mm = new TreeMap<> ();
mm.put("MM-1", m);
mm.put("MM-2", m);
System.out.println("MapMap");
Iterator<Iterator<String>> iiV = iiV(mm);
for (Iterator<String> i = new NestedIterator<>(iiV); i.hasNext();) {
System.out.print(i.next() + ",");
}
System.out.println();
}
private static void testMapMapMap() {
Map<String,String> m = new TreeMap<> ();
m.put("M-1", "V-1");
m.put("M-2", "V-2");
m.put("M-3", "V-3");
Map<String,Map<String,String>> mm = new TreeMap<> ();
mm.put("MM-1", m);
mm.put("MM-2", m);
Map<String,Map<String,Map<String,String>>> mmm = new TreeMap<> ();
mmm.put("MMM-1", mm);
mmm.put("MMM-2", mm);
System.out.println("MapMapMap");
Iterator<Iterator<Iterator<String>>> iiiV = iiiV(mmm);
for (Iterator<String> i = new NestedIterator<>(new NestedIterator<>(iiiV)); i.hasNext();) {
System.out.print(i.next() + ",");
}
System.out.println();
}
private static void testThreeWay() {
// Three way test.
System.out.println("Three way");
List<Iterator<I>> lii1 = Arrays.asList(
EnumSet.allOf(I.class).iterator(),
EnumSet.allOf(I.class).iterator(),
EnumSet.allOf(I.class).iterator(),
EnumSet.allOf(I.class).iterator());
List<Iterator<I>> lii2 = Arrays.asList(
EnumSet.allOf(I.class).iterator(),
EnumSet.allOf(I.class).iterator(),
EnumSet.allOf(I.class).iterator(),
EnumSet.allOf(I.class).iterator());
List<Iterator<I>> lii3 = Arrays.asList(
EnumSet.allOf(I.class).iterator(),
EnumSet.allOf(I.class).iterator(),
EnumSet.allOf(I.class).iterator(),
EnumSet.allOf(I.class).iterator());
Iterator<Iterator<Iterator<I>>> liii = Arrays.asList(
lii1.iterator(),
lii2.iterator(),
lii3.iterator()).iterator();
// Grow a 3-nest.
// Unroll it.
for (Iterator<I> ii = new NestedIterator<>(new NestedIterator<>(liii)); ii.hasNext();) {
I it = ii.next();
System.out.print(it + ",");
}
System.out.println();
}
private static void testTwoWay() {
System.out.println("Two way");
List<Iterator<I>> lii = Arrays.asList(
EnumSet.allOf(I.class).iterator(),
EnumSet.allOf(I.class).iterator(),
EnumSet.allOf(I.class).iterator());
for (Iterator<I> ii = new NestedIterator<>(lii.iterator()); ii.hasNext();) {
I it = ii.next();
System.out.print(it + ",");
}
System.out.println();
}
}
Your code can now look something like this. Note that I have not tested this at all and I have made use of Map instead of ConcurrentSkipListMap whenever possible and I am using the <> stuff from Java 7 to help out a LOT.
public class MyCustomIndex implements Iterable<byte[]> {
private Map<byte[], Map<byte[], Map<byte[], byte[]>>> table;
public MyCustomIndex() {
this.table = new ConcurrentSkipListMap<>();
}
/**
* #param K
* #param F
* #param Q
*/
public void put(byte[] K, byte[] F, byte[] Q) {
Map<byte[], byte[]> QToDummyValueMap;
Map<byte[], Map<byte[], byte[]>> FToQMap;
if (table.containsKey(K)) {
FToQMap = table.get(K);
if (FToQMap.containsKey(F)) {
QToDummyValueMap = FToQMap.get(F);
} else {
QToDummyValueMap = new ConcurrentSkipListMap<>();
}
} else {
QToDummyValueMap = new ConcurrentSkipListMap<>();
FToQMap = new ConcurrentSkipListMap<>();
}
QToDummyValueMap.put(Q, new byte[0]);
FToQMap.put(F, QToDummyValueMap);
table.put(K, FToQMap);
}
public Map<byte[], Map<byte[], Map<byte[], byte[]>>> gettable() {
return table;
}
public Iterator<byte[]> iterator () {
// **** This is what I have been aiming at all along ****
return new NestedIterator(new NestedIterator<>(NestedIterator.iiiV(table)));
}
}

Categories