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
Related
So I'm building a group of dropdowns that rely upon each other and built a query to get the code and description for a Product Type, Family, and Model object. I used nested hashmaps to story all of the data and objects. This was fine because I can just call all of the information that I need from the hashmaps. However, when it comes to the REST API's, it's going to display all of the nested information for each of the hashmaps when I call them. For each map I have it's key, and then the value consists of a Code, Desc, and the hashmap of the next object.
So, it would be like:
Main hashmap
- Key
- value
-> code
-> desc
-> product family hashmap
-- key
-- value
--> code
--> desc
--> product model hashmap
--- key
--- value
---> code
---> desc
My main question is how can I either strip these additional hashmaps from being displayed in the json format when viewing the REST API via web browser? Or can/do I need to just completely strip the additional information altogether?
#Service
public class ProductDAOImpl implements ProductDAO {
#PersistenceContext
private EntityManager em;
#Override
public Map<String, ProductType> getProductTypeStructure() {
HashMap<String, ProductType> prodTypes = new HashMap<>();
Query q = em.createNativeQuery("<query>");
List<Object[]> prodTypeEntities = q.getResultList();
final String badData = "XX-BAD-XX";
ProductType prodType = new ProductType(badData, "");
ProductFamily prodFamily = new ProductFamily(badData, "");
for(Object[] prodTypeEntity : prodTypeEntities) {
if (prodTypeEntity[1] == null || prodTypeEntity[3] == null || prodTypeEntity[5] == null) {
continue;
}
String prodTypeCd = prodTypeEntity[0].toString().toUpperCase();
String prodTypeDesc = StringUtils.trimTrailingWhitespace(prodTypeEntity[1].toString()).toUpperCase();
String prodFamilyCd = prodTypeEntity[2].toString().toUpperCase();
String prodFamilyDesc = StringUtils.trimTrailingWhitespace(prodTypeEntity[3].toString()).toUpperCase();
String prodModelCd = prodTypeEntity[4].toString().toUpperCase();
String prodModelDesc = StringUtils.trimTrailingWhitespace(prodTypeEntity[5].toString()).toUpperCase();
if(!prodType.getCode().equalsIgnoreCase(prodTypeCd)) {
prodType = new ProductType(prodTypeCd, prodTypeDesc);
prodType.setProdFamilies(new HashMap<String, ProductFamily>());
prodTypes.put(prodType.getCode(), prodType);
prodFamily.setCode(badData);
}
if(!prodFamily.getCode().equalsIgnoreCase(prodFamilyCd)) {
prodFamily = new ProductFamily(prodFamilyCd, prodFamilyDesc);
prodFamily.setProdModels(new HashMap<String, ProductModel>());
prodType.getProdFamilies().put(prodFamily.getCode(), prodFamily);
}
prodFamily.getProdModels().put(prodModelCd, new ProductModel(prodModelCd, prodModelDesc));
}
return prodTypes;
}
}
If I understood your question correctly, I think a DTO object might be the answer here. You add to it only the values that the dropdown might need and return it from the REST API.
Here's more on DTOs.
I have got two ArrayLists, created from parsed html. First one contains jobs and is like
Job A
Job B
Job C
and the second one is like
Company A
Company B
Company C
What I need is combination of Job A and Company A and so on, so I can get the results like (an ArrayList too would be great)
Job A : Company A
Job B : Company B
Job C : Company C
I didn't find clear tutorial or something. Any ideas?
Are you sure you are looking at the correct data structure to achieve this?
Why not use a Map? You can define a key/value relationship going this route.
Map<Company, Job> jobMap = new HashMap<Company, Job>();
jobMap.put("Company A" /* or corresponding list item */, "Job A" /* or corresponding list item */);
You may even do something like this: (Swap out the strings to your to fit your implementation)
Map<Company, List<Job>> jobMap...;
List<Job> jobList = new ArrayList<Job>();
jobList.add("Job A");
jobList.add("Job B");
jobList.add("Job C");
jobMap.put("Company A", jobList);
What this will do is define a company as your key and you can set multiple jobs to a company
if (jobs.length() != companies.length()) {
throw new InvalidArgumentException("Mismatch of jobs and companies");
}
for (int i = 0; i < jobs.length(); i++) {
combine(jobs.get(i), companies.get(i));
}
There are lots of ways to combine references between two kinds of objects. Here's a flexible example that will let you use one to look up the other. It's overkill if you know which you'd always be using to do the lookup. Using LinkedHashMap also preserves the insertion order. So if you decide to put them in B, C, A order, you can get them out in B, C, A order.
LinkedHashMap<Job, Company> jobToCompany = new LinkedHashMap<>();
LinkedHashMap<Company, Job> companyToJob = new LinkedHashMap<>();
private void combine(Job job, Company company) {
jobToCompany.put(job, company);
companyToJob.put(company, job);
}
If you really want to store the combined values in an ArrayList then the following code will work for you:
List<String> jobs = new ArrayList<>();
List<String> companies = new ArrayList<>();
List<String> mergedList = new ArrayList<>();
//assuming the value are populated for `jobs` and `companies`.
if(jobs.size() == companies.size()) {
int n = jobs.size();
for(int index=0; index<n; index++)
{
mergedList.add(jobs.get(index) + " : " + companies.get(index))
}
} else {
System.out.println("Cannot combine");
//Throw exception or take any action you need.
}
Keep in mind that if you need to search for any item it would be O(n) but I assume you are aware of it before taking decision of going with an ArrayList.
If you're not willing to use a Map (not sure why you would that) my approach would be: To create another class (lets call it CompanyJob) that would contain both a Company and a Job attribute, then simply have a collection of your CompanyJob instances (an ArrayList would do).
class CompanyList{
private Company mCompany;
private Job mJob;
public CompanyList (Company com, Job job){
mCompany = com;
mJob = job;
}
// Some logic ...
}
// Then your list
private ArrayList<CompanyList> yourList = new ArraList <>();
int i = 0;
for (Company tmpCom: companyList){
yourList.add (new CompanyJob (tmpCom,jobList.get(i));
i++;
}
You need to create a new one
List<String> third = new ArrayList<String>();
Also need a counter.
int position = 0;
Then iterate through the list (considering the size is same for both the list).
for(String item:firstList){
third.add(item+ " : " + secondList.get(position);
position ++;
}
Then the third will have the desired result.
To confirm:
for (String item:third){
//try to print "item" here
}
I want to store multiple custom key and value pair on Google Datastore entity inside the another model as a child entity. I found that there are two ways to do it
HashMap<String, String> map = new HashMap<String, String>()
(or)
List<KeyValuePair> pairs = new ArrayList<KeyValuePair>()
I really do not know which is correct method.
I also wanted to search by key and value pair which will be specified by the user to get the parent entity. The search also can have multiple key and value pair.
Please help me do it.
Google AppEngine Datastore writes and reads only simple Java data types listed in the Java Datastore Entities, Properties, and Keys documentation, not HashMap<String,String> or List<KeyValuePair> collections. However, it is possible to iterate over these collections and store each member as a separate record. The Datastore uses either a String or a long integer as the key (also known as ID or name) for each record. Thus the best fit for your Java program would be a HashMap<String,String>.
As you're open to suggestions, how about using the Datastore low level API instead of JDO? Your requirement is lightweight and a low level implementation might be simpler. For example:
// Make up some sample data
java.util.HashMap<String,String> capitals = new java.util.HashMap<String,String>();
capitals.put("France","Paris");
capitals.put("Peru","Lima");
// Create the records
com.google.appengine.api.datastore.DatastoreService datastoreService;
datastoreService = com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService();
for (String country : capitals.keySet()) {
com.google.appengine.api.datastore.Entity capitalEntity;
capitalEntity = new com.google.appengine.api.datastore.Entity("Capitals", country);
capitalEntity.setUnindexedProperty("capital", capitals.get(country)); // or setProperty if you prefer
datastoreService.put(capitalEntity);
}
// Retrieve one record
String wantedCountry = "Peru", wantedCapital;
com.google.appengine.api.datastore.Query query;
com.google.appengine.api.datastore.PreparedQuery pq;
com.google.appengine.api.datastore.Entity entity;
com.google.appengine.api.datastore.Key wantedKey;
com.google.appengine.api.datastore.Query.Filter filter;
query = new com.google.appengine.api.datastore.Query("Capitals");
wantedKey = com.google.appengine.api.datastore.KeyFactory.createKey("Capitals", wantedCountry);
filter = new com.google.appengine.api.datastore.Query.FilterPredicate(
com.google.appengine.api.datastore.Entity.KEY_RESERVED_PROPERTY,
com.google.appengine.api.datastore.Query.FilterOperator.EQUAL,
wantedKey );
query.setFilter(filter);
pq = datastoreService.prepare(query);
entity = pq.asSingleEntity();
wantedCapital = (String) entity.getProperty("capital");
// Retrieve all records
java.lang.Iterable<com.google.appengine.api.datastore.Entity> entities;
java.util.Iterator<com.google.appengine.api.datastore.Entity> entityIterator;
query = new com.google.appengine.api.datastore.Query("Capitals");
pq = datastoreService.prepare(query);
entities = pq.asIterable();
entityIterator = entities.iterator();
while (entityIterator.hasNext()) {
entity = entityIterator.next();
String foundCountry = entity.getKey().getName();
String foundCapital = (String) entity.getProperty("capital");
// ... do whatever you do with the data
}
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
}
A database call is made and result is a bunch of rows of two string columns of type A and B. e.g. (x_a, y_b), (x_a, y1_b), (x2_a,y_b)
The idea is to come up with a list of maps like {(x_a,{y_b,y1_b}), (x2_a,{y_b})} where the objects of type A are not repeated and to do this while pulling the results from a database.
Here's what I tried:
int i =0;
List<String> type2 = new ArrayList<String>();
Map<String,List<String>> type1_type2 = new HashMap<String,List<String>>();
List<Map> list_type1_type2 = new ArrayList<Map>();
String [] type1Array = new String[100];
String [] type2Array = new String[100];
int trackStart = 0;
while (res.next()){
String type1 = res.getString(1);
String type2 = res.getString(2);
type1Array[i]=type1;
type2Array[i] = type2;
if(i>0 && !type1Array[i].equals(type2Array[i-1])){
int trackStop = i;
for(int j = trackStart; j<trackStop;j++){
type2.add(type2Array[j]);
}
type1_type2.put(type1Array[i-1], type2);
list_type1_type2.add(type1_type2);
//debugging stuff
String x = list_type1_type2.toString();
System.out.println(x);
System.out.println(" printing because "+ type1Array[i]+" is not equal to " + type1Array[i-1]);
type2 = new ArrayList<String>();
type1_type2 = new HashMap<String,List<String>>();
trackStart=i;
}
i++;
}
This method does not work when the last type1 values of the result object are the same.
Is there a way to do this in the same spirit (within the while(res.next)) without first storing the results of the database call in separate arrays or adding an extra for loop outside the while loop to "patch it up"?
The simple way to do this is to use a Guava / Google Collections SetMultiMap. This is essentially a mapping from a key (your 'A' objects) to a set of values (your 'B' objects).
[I'm not going to try to code it for you. Your current code is too horrible to read ... unless you were paying me :-) ]
However, a better idea would be to get the database to do the collation. If you can do that, you will reduce the amount of (redundant) data that gets send across the database connection ... assuming that you are using JDBC.
If you don't want duplicates like {x_a:[y_b, y_b]} then use a set as the value of your map:
Map<String,Set<String>> type1_type2;
I don't know what the other various list and arrays are for. You can probably just get by with the type1_type2 map. Process each (x, y) in pseudo-code:
Set s = type1_type2.get(x)
if s == null:
s = new Set()
type1_type2.put(x, s)
s.add(y)