I'm having a tough time wrapping my head around the following situation. The best way to explain may be by example
I have a Map<Column,Set<Row>> object.
Let's say it contains the following data:
ColumnA['abc','def']
ColumnB['efg','hij','klm']
ColumnC['nop']
ColumnD['qrs','tuv','wxy','zzz']
I am trying to generate the following output:
Row1[abc,efg,nop,qrs]
Row2[abc,efg,nop,tuv]
Row3[abc,efg,nop,wxy]
Row4[abc,efg,nop,zzz]
Row5[abc,hij,nop,qrs]
Row6[abc,hij,nop,wxy]
etc...
So in this case there would be 24 rows total.
However, the number of columns and rows are both dynamic. I feel like this needs to be recursively done somehow but I'm not sure where to start.
Any help would be appreciated.
Update - I made a Tree structure that seems to work.
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
Set<DefaultMutableTreeNode> curNodes = new HashSet<DefaultMutableTreeNode>();
curNodes.add(root);
final Set<Column> keys = map.keySet();
for (final Column key : keys) {
final Set<Row> rowSet = map.get(key);
Set<DefaultMutableTreeNode> tmpNodes = new HashSet<DefaultMutableTreeNode>();
for (final Row row : rowSet) {
DefaultMutableTreeNode curNode = new DefaultMutableTreeNode();
curNode.setUserObject(row);
tmpNodes.add(curNode);
for (DefaultMutableTreeNode n : curNodes) {
n.add(curNode);
}
}
curNodes = tmpNodes;
}
I hope this is not some student's homework.
First to keep the order of the map's keys the same, use a SortedMap, like TreeMap.
Furthermore in your initial map every Row contains just a single value like 'abc'.
Recursion here is a depth-first traversal. The hard thing is that a map has not a
natural traversal. For the rest have todos/candidates and dones/result; do a step changing data and afterwards restore them.
Here I use the more known List, but a Stack would be nicer.
public List<Row> generateRows(SortedMap<Column, Set<Cell>> map) {
List<Row> done = new ArrayList<Row>();
List<Column> columnsToDo = new LinkedList<Column>(map.keySet());
List<Cell> partialRow = new LinkedList<Cell>();
generateRowsRec(map, columnsToDo, partialRow, done);
return done;
}
void generateRowsRec(SortedMap<Column, Set<Cell>> map, List<Column> columnsToDo, List<Cell> partialRow, List<Row> done) {
if (columnsToDo.isEmpty()) {
done.add(new Row(partialRow));
return;
}
Column firstColumn = columnsToDo.remove(0); // Step A
for (Cell cell : map.get(firstColumn)) {
partialRow.add(cell); // Step B
generateRowsRec(map, columnsToDo, partialRow, done);
partialRow.remove(partialRow.size() - 1); // Unstep B
}
columnsToDo.add(0, firstColumn); // Unstep A
}
Related
I have a HashMap<GC, List<RR>> with sample data like:
key values
gc1 - rr1
- rr2
- rr3
gc2 - rr4
- rr5
gc3 - rr6
And I need to create all possible combinations of RR from different GC like:
Combination1: rr1, rr4, rr6
Combination2: rr1, rr5, rr6
Combination3: rr2, rr4, rr6
Combination4: rr2, rr5, rr6
Combination5: rr3, rr4, rr6
Combination6: rr3, rr5, rr6
What I've tried so far is, as #Sanket Makani suggests, to turn my HashMap<GC, List<RR>> into a List<List<RR>>, and then iterate through all the elements like:
List<List<RR>> inputList = new ArrayList<List<RR>>();
for (Map.Entry<GC, List<RR>> rrList : Map.entrySet()) {
inputList.add(rrList.getValue());
}
List<List<RR>> combinationsList = new ArrayList<List<RR>>();
for (List<RR> rrList : inputList) {
List<RR> rrList1 = new ArrayList<RR>();
for (RR rr : rrList) {
rrList1.add(rr);
}
combinationsList.add(rrList1);
}
This is not working for me, as it groups all the RR inside one GC like:
Combination1: rr1, rr2, rr3
Combination2: rr4, rr5
Combination3: rr6
So my quesiton is, how can I adapt my code to obtain the expected result?
PS: I'm working with Java6 unfortunately, so no lambdas/streams allowed.
PS2: I've seen similar questions, but can't find and exact example of what I'm looking for.
EDIT:
This is my final implementation with #nandsito's answer:
//this method groups RRs by GC key with a given list
HashMap<GC, List<RR>> GCRRHashMap = groupRRsByGC(list);
List<Map.Entry<GC, List<RR>>> mapEntryList = new ArrayList<Map.Entry<GC, List<RR>>>(GCRRHashMap.entrySet());
List<List<RR>> combinationsList = new ArrayList<List<RR>>();
List<RR> combinations = new ArrayList<RR>();
generateCombinations(mapEntryList, combinations, combinationsList);
private void generateCombinations(
List<Map.Entry<GC, List<RR>>> mapEntryList,
List<RR> combinations, List<List<RR>> combinationsList) {
if (mapEntryList.isEmpty()) {
combinationsList.add(new ArrayList<RoomStay>(combinations));
return;
}
Map.Entry<GC, List<RR>> entry = mapEntryList.remove(0);
List<RR> entryValue = new ArrayList<RR>(entry.getValue());
while (!entryValue.isEmpty()) {
RR rr = entryValue.remove(0);
combinations.add(rr);
generateCombinations(mapEntryList, combinations, combinationsList);
combinations.remove(combinations.size() - 1);
}
mapEntryList.add(0, entry);
}
Here's a recursive solution:
public static void main(String[] args) {
// your data map
Map<GC, List<RR>> map;
// the map entry set as list, which will help
// combining the elements
//
// note this is a modifiable list
List<Map.Entry<GC, List<RR>>> mapEntryList =
new ArrayList<Map.Entry<GC, List<RR>>>(map.entrySet());
// the combinations list, which will store
// the desired results
List<RR> combinations = new ArrayList<RR>();
doRecursion(mapEntryList, combinations);
}
private static void doRecursion(
List<Map.Entry<GC, List<RR>>> mapEntryList,
List<RR> combinations) {
// end of recursion
if (mapEntryList.isEmpty()) {
// do what you wish
//
// here i print each element of the combination
for (RR rr : combinations) {
System.out.println(rr);
}
System.out.println();
return;
}
// remove one GC from the entry list,
// then for each RR from the taken GC
// put RR in the combinations list,
// call recursion
// the remove RR from the combinations list
// end for each
// then put GC back into its list
Map.Entry<GC, List<RR>> entry = mapEntryList.remove(0);
List<RR> entryValue = new ArrayList<RR>(entry.getValue());
while (!entryValue.isEmpty()) {
RR rr = entryValue.remove(0);
combinations.add(rr);
doRecursion(mapEntryList, combinations);
combinations.remove(combinations.size() - 1);
}
mapEntryList.add(0, entry);
}
All you really need to do is work through an incrementing index list:
0,0,0
0,1,0
1,0,0
1,1,0
2,0,0
... etc.
It should be obvious how to translate each of those rows into to values from your data structure. e.g. 0,0,0 maps to rr1, rr4, rr6. This will involve converting the map into a list so that indexes are consistent.
It's very much like a normal base-b count where you increment the rightmost column and if it overflows, set to zero and increment the next one. The only difference is that each column overflows at a different number.
So:
boolean increment(int[] indexes) {
int column = 0;
while(true) {
indexes[column]++;
if(indexes[column] < numberOfRRsInColumn(column)) {
return true; // finished
}
indexes[column]=0;
column++;
if(column = indexes.length) {
return false; // can't increment, no more.
}
}
}
This implementation uses indexes[0] as the "rightmost" column. I've glossed over numberOfRRsInColumn(), but it should be pretty obvious how to do it.
Then:
int[] indexes = new int[mapsize];
do {
output(translate(map, indexes));
} while (increment(indexes));
I have a graph, and i want to give each node different value, because i want to calculate every node's betweenness ,predecessor and so on,
but i think if i use map, the former value will be replaced. how can i figure out that ? Following is my code. I try to use map
LinkedHashMap<Vertex<E>, Double> Betweenness = new LinkedHashMap<>();
for(Vertex<E> vertex : graph.vertexSet())
{
Betweenness.put(vertex,0.0);
}
for(Vertex<E> vertex : graph.vertexSet())
{
//Create stack to keep track of vertices in order to calculate value of flow
StackADT<Vertex<E>> processingStack = new LinkedStack<Vertex<E>>();
LinkedHashMap<Vertex<E> ,List<Vertex<E>>> Predecessor = new LinkedHashMap<>();
for(Vertex<E> predecessorofVertex : graph.vertexSet())
{
List<Vertex<E>> PredecessorList = new LinkedList<>();
Predecessor.put(predecessorofVertex, PredecessorList);
}
}
I have a database with two columns named
colNode,colLeaf
When I read data from the database and display it on the JTree
while (resultSet.next()) {
DefaultMutableTreeNode url = new DefaultMutableTreeNode(resultSet.getString("colNode"));
mutableTreeNode.add(url);
url.add(new DefaultMutableTreeNode(resultSet.getString("colLeaf")));
}
I would like if the value already exists on JTree colNode then colLeaf will be appended to the.I want to get the results in Figure 2
Please help me
Current output:
Desired output:
I assume you mean, that you want to group all the colLeaf with the same colNode?
I'd start by doing one of two things, either use the SQL to group and/or sort your results by colNode, this way you could monitor the current "group" and when it changes, create a new TreeNode
Something like...
DefaultMutableTreeNode rootNode = ...;
DefaultMutableTreeNode groupNode = null;
String currentGroup = null;
while (resultSet.next()) {
String group = resultSet.getString("colNode");
if (currentGroup == null || !currentGroup.equals(group)) {
currentGroup = group;
group = new DefaultMutableTreeNode(group);
rootNode.add(groupNode);
}
group.add(new DefaultMutableTreeNode(resultSet.getString("colLeaf")));
}
for example.
Or, use somekind of Map, to map all the colNode values under the same key (colLeaf)
Map<String, List<String>> mapGroups = new HashMap<>(25);
while (resultSet.next()) {
String group = resultSet.getString("colNode");
List<String> members = mapGroups.get(group);
if (members == null) {
members = new ArrayList<>(25);
mapGroups.put(group, members);
}
members.add(resultSet.getString("colLeaf"));
}
You would then use the mapGroups to generate your TreeNodes based on the key/value groups.
for example.
Personally, I think the first option is more efficient, but might require a more complex query, the second option is slower and requires more overhead, but models the data in manner which is similar to that which you are trying to achieve
I am using myBatis 3.2.x and have run into a scenario where I need to do multiple table inserts in one database trip,
I was wondering if I can create a master INSERT sql mapper file which would call these multi table inserts and save me network trips
I am consuming JSON objects from a EMS server and my Turn around time is a bit higher then required.
All suggestions and hints are welcome.
Thanks
VR
Use Collections.sort() to sort and use a simple for cycle to catch doubles, e.g.:
Collections.sort(myList);
A previous = null;
for (A elem: myList) {
if (elem.compareTo(previous) == 0) {
System.err.println("Duplicate: "+elem);
}
previous = elem;
}
Assuming that the Comparable is consistent with the equals implementation, you can use a Set. You can add each element to a Set using Set.add(..) and use the return value of add to determine if the value was already present in the Set and create either a Set or a List to return.
Note: If you need each duplicate returned only once, you can change the return list to a set.
List<A> duplicates(List<A> myList) {
Set<A> s = new HashSet<A>();
List<A> duplicates = new ArrayList<A>(); // change to using a Set if you want to report each duplicate item only once.
for (A item: myList) {
if (!s.add(item)) {
duplicates.add(item);
}
}
return duplicates;
}
An improved version using sorting (to report duplicate elements only once, I assume there are no null values in the list):
Collections.sort(myList);
A previous = null, elem = null;
for (java.util.Iterator<A> it = myList.iterator; it.hasNext(); elem = it.next()) {
if (elem.compareTo(previous) == 0) {
System.err.println("Duplicate: "+elem);
while (it.hasNext() && (elem = it.next()).compareTo(previous)) {
//loop through other values
}
}
previous = elem;
}
A version using SortedSet (probably this is faster a bit): and corrected the same
SortedSet<A> set = new TreeSet<>(), duplicates = new TreeSet<>();
for (A a: myList) {
if (!set.add(a)) {
duplicates.add(a);
}
}
return duplicates;//or for (A a: duplicates) System.println("Duplicate: " + a);
I need to modify the insert method of my program so that it inserts items into a singly linked list in ascending order. I understand what a linked list is but have no clue how to insert the items in order. Here are my programs so far(not the entire program):
public class SinglySortedLinkedList
{ private Node h; // list header
public SinglySortedLinkedList()
{ h = new Node(); // dummy node
h.l = null;
h.next = null;
}
public boolean insert(Listing newListing)
{ Node n = new Node();
if(n == null) // out of memory
return false;
else
{
n.next = h.next;
h.next = n;
n.l = newListing.deepCopy();
return true;
}
}
here is the tester method:
public class MainSinglyLinkedList
{ public static void main(String[] args)
{ SinglySortedLinkedList boston = new SinglySortedLinkedList();
Listing l1 = new Listing("Bill", "1st Avenue", "123 4567" );
Listing l2 = new Listing("Al", "2nd Avenue", "456 3232");
Listing l3 = new Listing("Mike", "3rd Avenue", "333 3333");
boston.insert(l1); // test insert
boston.insert(l2);
boston.insert(l3);
boston.showAll();
l3 = boston.fetch("Mike"); // test fetch of Mike
System.out.println(l3.toString());
boston .delete("Al"); // test delete of Al
boston.showAll();
boston.update("Mike", l2); // test update of Mike to Al
boston.showAll();
System.exit(0);
}
}
Any ideas of some pseudocode of how to insert in ascending order by the names would be so great, thanks
I don't want to do your homework, but I'll give you hints. If you have more specific questions then, you will probably find answers in SO. In the unlikely situation where you don't, feel free to ask a new question ;)
First, you need to find the point in the list where you want to insert, and then insert your Node n (containing the new Listing) at that point. This can be done using a while loop, with a comparison between listings as a condition, which in english would be said:
while the listing of the current node is inferior to the listing I
want to insert, I keep on going
For how to do this kind of comparison on Strings in Java, have a look at the compareTo method.
Then, use your former piece of code to insert n there. See the note below to see what I have to say about it and your dummy Node.
Side note
You're using a "dummy node" for your list header, and always insert after that one.
This is probably not necessary, you could insert each new Node in place of h and make it point to the former h, which would be both cleaner and easier to read IMHO.
Instead of:
n.next = h.next;
h.next = n;
n.l = newListing.deepCopy();
You could have:
n.next = h; // here n's next points to the former head h
h = n; // now n in the new head referenced by h
n.l = newListing.deepCopy();
This way, you don't even need a dummy node anymore, null is fine to set the n.next field. It'll also probably simplify your fetch method.