Created
November 16, 2020 09:15
-
-
Save spattanaik75/584b34acb5d98decc8794299411740bc to your computer and use it in GitHub Desktop.
Find shortest path from one table to another table
This file contains 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 java.util.*; | |
import java.util.stream.Collectors; | |
public class TableRelation { | |
public static void main(String[] args) { | |
ArrayList<Table> tablesList = new ArrayList<Table>(); | |
// tableColumnDetails | |
Table employeTable = new Table("Employee"); | |
employeTable.addColumn(new Column("EmployeeName", false, null)); | |
employeTable.addColumn(new Column("EmployeeAge", false, null)); | |
employeTable.addColumn(new Column("EmployeeLocation", true, new ForeignKeyRelation("Location", "LocationName"))); | |
employeTable.addColumn(new Column("AssiagnedVehicle", true, new ForeignKeyRelation("Vechicles", "VehicleName"))); | |
employeTable.addColumn(new Column("EmployeeDepartment", true, new ForeignKeyRelation("Department", "DepartmentName"))); | |
Table locationTable = new Table("Location"); | |
locationTable.addColumn(new Column("LocationName", false, null)); | |
locationTable.addColumn(new Column("LocationPincode", false, null)); | |
locationTable.addColumn(new Column("LocationAdmin", true, new ForeignKeyRelation("Employee", "EmployeeName"))); | |
Table departmentTable = new Table("Department"); | |
departmentTable.addColumn(new Column("DepartmentName", false, null)); | |
departmentTable.addColumn(new Column("DepartmentRevenue", false, null)); | |
departmentTable.addColumn(new Column("DepartmentHead", true, new ForeignKeyRelation("Employee", "EmployeeName"))); | |
Table productTable = new Table("Product"); | |
productTable.addColumn(new Column("ProductName", false, null)); | |
productTable.addColumn(new Column("ProductUnitPrice", false, null)); | |
productTable.addColumn(new Column("ProductStock", false, null)); | |
Table ordersTable = new Table("Orders"); | |
ordersTable.addColumn(new Column("OrderProduct", true, new ForeignKeyRelation("Product", "ProductName"))); | |
ordersTable.addColumn(new Column("OrderQuantity", false, null)); | |
ordersTable.addColumn(new Column("OrderBy", true, new ForeignKeyRelation("Employee", "EmployeeName"))); | |
Table vechiclesTable = new Table("Vechicles"); | |
vechiclesTable.addColumn(new Column("VehicleName", false, null)); | |
vechiclesTable.addColumn(new Column("VehicleTopSpeed", false, null)); | |
// below is the relations | |
tablesList.add(employeTable); | |
tablesList.add(locationTable); | |
tablesList.add(departmentTable); | |
tablesList.add(productTable); | |
tablesList.add(ordersTable); | |
tablesList.add(vechiclesTable); | |
// Input for the program | |
Scanner scanner = new Scanner(System.in); | |
System.out.println("Enter Table1:"); | |
String table1 = scanner.next(); | |
System.out.println("Enter Table2:"); | |
String table2 = scanner.next(); | |
System.out.println("input : " + table1 + " to " + table2); | |
/* | |
develop logic to detect relation between tables | |
Refer the image for better understanding of the relationship | |
Output Format: | |
Table --> Table(PrevTableCol,CurrentTableCol) --> Table(PrevTableCol,CurrentTableCol) --> ..... | |
PrevTableCol,CurrentTableCol are directly related or indirectly if both tables has same foreign key | |
-------------------------------------------------------------------------------------------------------------- | |
example: | |
-------------------------------------------------------------------------------------------------------------- | |
Input: Vechicles to Employee | |
Ouput: | |
Shortest path: | |
Output --> Vechicles --> Employee(VehicleName,AssiagnedVehicle) | |
All possible path | |
... <Print all possible paths, refer Usecase1.JPG> ............. | |
-------------------------------------------------------------------------------------------------------------- | |
Input: Department to Orders | |
Ouput: | |
Shortest path: | |
Output --> Department --> Orders(DepartmentHead,OrderBy) | |
All possible path | |
... <Print all possible paths, refer Usecase2.JPG> ............. | |
-------------------------------------------------------------------------------------------------------------- | |
Input: Product to Vehicles | |
Ouput: | |
Shortest path: | |
Output --> Product --> Orders(ProductName,OrderProduct) --> Employee(OrderBy,EmployeeName) --> Vehicles(AssiagnedVehicle,VehicleName) | |
All possible path | |
... <Print all possible paths, refer Usecase3.JPG> ............. | |
-------------------------------------------------------------------------------------------------------------- | |
Note: | |
1. We need to execute this logic for N(say 100) tables and finding the relationship path should be in shortest time | |
2. We need both outputs | |
A. Shortest path | |
B. All possible paths | |
3. Two table are inter-related if they have same foreign key (for example: LocationAdmin, DeptHead and OrderBy are related) | |
4. Please refer the image for better understanding | |
*/ | |
GraphTraversal gt = new GraphTraversal(tablesList); | |
// Construct Graph | |
tablesList.forEach( | |
table -> { | |
table.tableColumns.stream() | |
// filter only foreign keys | |
.filter(column -> column.isForeignKey) | |
.forEach(column -> { | |
gt.addRelation(table.tableName, column.ForeignKeyRelation.foreignTable, | |
column.columnName, column.ForeignKeyRelation.foreignTableColumn); | |
tablesList.forEach(table3 -> { | |
table3.tableColumns.stream() | |
// filter only foreign keys | |
.filter(column1 -> column1.isForeignKey) | |
.forEach(column1 -> { | |
if (!table.tableName.equals(table3.tableName) | |
&& column1.ForeignKeyRelation.foreignTableColumn.equals(column.ForeignKeyRelation.foreignTableColumn)) { | |
gt.addRelation(table3.tableName, table.tableName, | |
column1.columnName, column.columnName); | |
} | |
}); | |
}); | |
} | |
); | |
} | |
); | |
// generate All Paths | |
gt.generateAllPaths(table1, table2); | |
// print All possible paths | |
List<String> allPossiblePaths = gt.getAllPossiblePaths(); | |
String shortestPath = allPossiblePaths.get(0); | |
for (String str : allPossiblePaths) { | |
if (str.length() < shortestPath.length()) { | |
shortestPath = str; | |
} | |
} | |
System.out.println("Shortest path:"); | |
System.out.println("Output --> " + shortestPath); | |
System.out.println("All possible path:"); | |
allPossiblePaths.stream().forEach(path -> System.out.println("Output --> " + path)); | |
} | |
static class ForeignKeyRelation { | |
String foreignTable; | |
String foreignTableColumn; | |
public ForeignKeyRelation() { | |
// TODO Auto-generated constructor stub | |
} | |
public ForeignKeyRelation(String foreignTable, String foreignTableColumn) { | |
this.foreignTable = foreignTable; | |
this.foreignTableColumn = foreignTableColumn; | |
} | |
} | |
static class Column { | |
String columnName; | |
boolean isForeignKey; | |
ForeignKeyRelation ForeignKeyRelation; | |
public Column() { | |
// TODO Auto-generated constructor stub | |
} | |
public Column(String columnName, boolean isForeignKey, ForeignKeyRelation ForeignKeyRelation) { | |
this.columnName = columnName; | |
this.isForeignKey = isForeignKey; | |
this.ForeignKeyRelation = ForeignKeyRelation; | |
} | |
} | |
static class Table { | |
String tableName; | |
ArrayList<Column> tableColumns = new ArrayList<Column>(); | |
public Table() { | |
} | |
public Table(String tableName) { | |
this.tableName = tableName; | |
} | |
public Table addColumn(Column column) { | |
tableColumns.add(column); | |
return this; | |
} | |
} | |
} | |
class GraphTraversal { | |
// No of tables | |
private final List<TableRelation.Table> tablesList; | |
// List of related Classes | |
private Map<String, ArrayList<String>> relationMap = new HashMap<>(); | |
private List<String> allPossiblePaths = new ArrayList<>(); | |
public List<String> getAllPossiblePaths() { | |
return allPossiblePaths; | |
} | |
// Constructor | |
public GraphTraversal(List<TableRelation.Table> tablesList) { | |
this.tablesList = tablesList; | |
initRelationList(); | |
} | |
private void initRelationList() { | |
tablesList.forEach(table -> relationMap.put(table.tableName, new ArrayList<>())); | |
} | |
/** | |
* Add relation between source to destination | |
* | |
* @param source: source table name | |
* @param dest: destination table name | |
* @param s1: source relationship column | |
* @param d1: destination relationship column | |
*/ | |
public void addRelation(String source, String dest, String s1, String d1) { | |
// format is "destination(s1,d1)" | |
String sourceRelation = dest + "(" + s1 + "," + d1 + ")"; | |
String destRelation = source + "(" + d1 + "," + s1 + ")"; | |
// add relation to source | |
if (!relationMap.get(source).contains(sourceRelation)) { | |
relationMap.get(source).add(sourceRelation); | |
} | |
// add relation to destination | |
if (!relationMap.get(dest).contains(destRelation)) { | |
relationMap.get(dest).add(destRelation); | |
} | |
} | |
/** | |
* Print all paths from source to destination | |
* | |
* @param source | |
* @param destination | |
*/ | |
public void generateAllPaths(String source, String destination) { | |
List<String> isVisited = new ArrayList<>(); | |
List<String> pathList = new ArrayList<>(); | |
// add source to path | |
pathList.add(source); | |
// all paths from source to destination | |
pathsUtil(source, destination, isVisited, pathList); | |
pathList.remove(source); | |
pathList.add(destination); | |
// all paths from destination to source | |
pathsUtil(destination, source, isVisited, pathList); | |
} | |
/** | |
* Recursive print path helper | |
* | |
* @param currentNode | |
* @param destination | |
* @param isVisited | |
* @param localPathList | |
*/ | |
private void pathsUtil(String currentNode, | |
String destination, | |
List<String> isVisited, | |
List<String> localPathList) { | |
if (destination.equals(currentNode)) { | |
// System.out.println(String.join(" --> ", localPathList)); | |
this.allPossiblePaths.add(String.join(" --> ", localPathList)); | |
return; | |
} | |
isVisited.add(currentNode); | |
this.relationMap.forEach((nodeName, value) -> { | |
List<String> currentNodePaths = this.relationMap.get(currentNode); | |
if (!isVisited.contains(nodeName)) { | |
List<String> validPaths = currentNodePaths.stream() | |
.filter(path -> path.contains(nodeName + "(")) | |
.collect(Collectors.toList()); | |
validPaths.forEach( | |
path -> { | |
localPathList.add(path); | |
pathsUtil(nodeName, destination, isVisited, localPathList); | |
localPathList.remove(path); | |
} | |
); | |
} | |
}); | |
isVisited.remove(currentNode); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment