I want to iterate through a hibernate query results inside stringtemplate. I've been looking for examples but I can't find anything.
can you please help? thanks
The syntax looks like
<items :{ item | <item> }>
Putting it together in Java:
List<String> teams = Arrays.asList("Cats", "Birds", "Turtles");
ST s = new ST( "<teams :{team | <team> }>");
s.add("teams", teams);
System.out.println(s.render());
In this example, I iterate over the List and print each team that is in the teams list. The result that would be printed is:
Cats Birds Turtles
We can explore the syntax that makes this happen. Before we do, remember, that the default delimiters in StringTemplate are less than < and greater than >. Since we didn't specify a different delimiter < > will be what we use in our example.See more about delimiters
:{ }
This set of symbols, the colon : and the open and closed brace {} can be read as "for each". In the example template, the code reads, for each team in teams print team. The left side of the vertical pipe | indicates the variable that will be created for each iteration. It will hold the current team from the list of teams. The print is composed of the <team> on the right side of the vertical pipe | and the left side of the closing brace }. Anything that is on the right side of the vertical pipe | and before the closing base } will be evaluated to be printed.
:{ current value | everything in here will be printed }
In order to build on the concept, let's use a more complex data structure.
public class Player {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() { return age; }
public String getName() { return name; }
}
Now we can create a few players for our team:
Player[] players = new Player[] {
new Player("Bill", 29),
new Player("Steve", 30),
new Player("Toby", 15)
};
String playerTemplate = "<players:{ player |<player.name> is <player.age> <\\n>}>"
ST s = new ST( playerTemplate );
s.add("players", Arrays.asList(players));
System.out.println(s.render());
Giving a result of
Bill is 29
Steve is 30
Toby is 15
Couple of things to note. We didn't access the properties age and name directly. ST called the methods getAge and getName. ST doesn't look to the properties. Instead, it looks to find the access methods.
What if we just wanted to iterate over a list that contained another list. We can do that as well.
First, let's build up our data structure and fill it with a couple of lists.
List<List<String>> listOfLists = asList(
asList("One", "Two", "Three"),
asList("Four", "Five"),
asList("Six", "Seven", "Eight", "Nine")
);
The template will look like the following.
<list :{ items |<items :{ item |<item> }><\n>}>
Our template, in this case, will just be a combination. The outer shell will iterate over the list we will hand in.
<list :{ items | what we will print }>
Then for each item, we will print out the items in its list.
<items :{ item |<item> }>
Once we put it all together
String template = "<list :{ items |<items :{ item |<item> }><\\n>}>";
ST st = new ST( template);
st.add("list", listOfLists);
System.out.println(st.render());
We get a result that looks like the following.
One Two Three
Four Five
Six Seven Eight Nine
Building on this concept a little more we can create a second data structure that contains a list of players. This will demonstrate how to iterate within iteration.
The first thing we will need is a data structure that contains a list. For this we can create a Team for our players to be a part.
public class Team {
private List<Player> players;
private String name;
public Team (String name, List<Player> players) {
this.players = players;
this.name = name;
}
public List<Player> getPlayers() {
return players;
}
public String getName() {
return name;
}
}
Notice that our team contains players. This composition will allow us to build up two iterations.
Now that we have our data structure lets set everything together to make a couple of teams with some players.
List<Team> teams = asList(
new Team("Billings", asList(
new Player("Bill", 29),
new Player("Steve", 30),
new Player("Toby", 15)
)),
new Team("Laurel", asList(
new Player("Chad", 32),
new Player("Chuck", 29),
new Player("Will", 24),
new Player("Ben", 26)
))
);
Now lets create a template and fill in a few details:
String simpleTeamTemplate = "<teams:{ team |<team.name> has <length(team.players)> players<\\n>}>";
ST template = new ST( simpleTeamTemplate );
template.add("teams", teams);
System.out.println(template.render());
That will print out
Billings has 3 players
Laurel has 4 players
Our simple template is just about the same as our first template from above. The only real difference is that we are using a built-in method provided by ST length(). See more on functions here
Let's increase the complexity of the templates a little to add in our second iteration.
First, we will create our playersTemplate. This is almost identical to our playerTemplate template from above. The only difference is that we have our players coming from a team: team.players.
String playersTemplate = "<team.players :{ player |<player.name> is <player.age><\\n>}>";
Now we will construct a second template that contains the first. In this template we can iterate over teams and for each team we will print out the name, number of players length(team.players), and everything in the playersTemplate.
String teamTemplate = "<teams:{ team |<team.name> has <length(team.players)> players<\\n>"+playersTemplate+"}>";
Now let's put that all together.
ST teamsTemplate = new ST( simpleTeamTemplate);
teamsTemplate.add("teams", teams);
System.out.println(teamsTemplate.render());
That will print for us the following.
Billings has 3 players
Bill is 29
Steve is 30
Toby is 15
Laurel has 4 players
Chad is 32
Chuck is 29
Will is 24
Ben is 26
Now, you aren't really going to want to combine your templates in this way. Appending strings together to compose templates is rather silly. StringTemplate offers tools to make this combination of partial templates very easy. If you are curious about combining templates you can find out more here
%staffForOrg: {staff|
<tr>
<td>%staff.telephoneNumber%</td>
</tr>
}%
this code works perfectly.
staffForOrg is a list of my model. I used hibernate to retrieve the records.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have data type of the following format:
Popularity:xx
Name:xx
Author:xx
Sales:xx
Date Published: xx
I am free to choose whatever way I can store my data in.
I will need to perform some queries on the data, for example
What are the top 'N' Books for the year 'M'
What are the average sales of the top 'N' songs for author 'X'?
It should be kept in mind that further queries may be added.
What will be the different ways to represent the data to perform the queries (in Java)? What will be the merits?
Note: (Not looking for a DB solution)
JDK comes bundled with Java DB and seems perfectly fine for your use case.
Edit: Sorry I misread the question as a dB solution because it seems you need it. That said you should look for a DB solution where you just query your books from.
If you actually do want to perform queries on data-structures in memory you can use Apache Commons Collections which support filtering.
If you do want to use a data-structure like a Vector which seems like a solution, you need to build indexes to improve performance. Then lookup in the indices and get the book needed. If you know which searches are necessary you can group chosen indexes and create a block to easily search. Essentially creating your own cube data-structure. Could be a nice project.
Arraylist of a class. Create a class with those variables as, well, class variables, then instantiate an Arraylist of said object. Then you can perform searches based on the values of certain variables. For example:
//replace "ClassName" with the name of the class
ArrayList<"ClassName"> array = new ArrayList<"ClassName">();
ArrayList<"ClassName"> results = new ArrayList<"ClassName">();
for("ClassName" obj:array)
{
if(obj.getAuthor().equals("Author Name"))
{
results.add(obj);
}
}
There are many ways to sort the results, including using Collections.sort(); which seems to be the best way to go about it.
Sort ArrayList of custom Objects by property
EDIT: I went ahead and gave you an example based on the specific case you outlined in the comments. This should help you out a lot. As stated before, I had a similar issue for a lab in University, and this was a way I did it.
You could use a Bean to wrap your data:
public class Record {
int popularity;
String name;
String author;
int sales;
int yearPublished;
public Record(int popularity, String name, String author, int sales, int yearPublished) {
super();
this.popularity = popularity;
this.name = name;
this.author = author;
this.sales = sales;
this.yearPublished = yearPublished;
}
//getter and setter...
public String toString(){
return name;
}
And this is a typical usage querying with java8:
Record Record1 = new Record(10,"Record 1 Title","Author 1 Record",10,1990);
Record Record2 = new Record(100,"Record 2 Title","Author 2 Record",100,2010);
Record Record3 = new Record(140,"Record 3 Title","Author 3 Record",120,2000);
Record Record4 = new Record(310,"Record 4 Title","Author 1 Record",130,2010);
Record Record5 = new Record(110,"Record 5 Title","Author 5 Record",140,1987);
Record Record6 = new Record(160,"Record 6 Title","Author 1 Record",15,2010);
Record Record7 = new Record(107,"Record 7 Title","Author 1 Record",4,1980);
Record Record8 = new Record(1440,"Record 8 Title","Author 8 Record",1220,1970);
Record Record9 = new Record(1120,"Record 9 Title","Author 9 Record",1123,2010);
List<Record> Records = Arrays.asList(Record1,Record2,Record3,Record4,Record5,Record6,Record7,Record8,Record9);
//top 2 record of year 2010
int m = 2;
int year = 2010;
System.out.println(Arrays.toString(Records.stream().filter(s -> s.getYearPublished() == year).sorted((r1, r2) -> Integer.compare(r2.popularity, r1.popularity)).limit(m).toArray()));
//average top 2 record of Author 1 Record
String author= "Author 1 Record";
int n = 2;
System.out.println(Records.stream().filter(s -> author.equals(s.getAuthor())).sorted((r1, r2) -> Integer.compare(r2.popularity, r1.popularity)).limit(n).mapToInt(Record::getSales).average().getAsDouble());
This prints:
[Record 9 Title, Record 4 Title]
72.5
Having a collection of objects you can use stream api to collect/filter/reduce your results. There is not so much to it.
The main problem is to not load all of the objects to memory and to be able to retrieve them from whatever store efficiently by using indexes, reverse-indexes.
One of the frameworks which came to my mind is Apache spark
I am using Java, MySQL and iReport-3.7.6. I need to create a report with two tables. One contains Machine Production details other contains employees working in a shift. It should print date and shift wise.
I can merge employees against machines. Because there are one or more employees works in two or three same machines.
I need to get a report like the one below.
Date:04-03-2015 Shift - I
Sno Supervisor Machines Employees
-----------------------------------------------------------
1 Arun 1,2,4 Siva,Raj,Ram,James
2 Kumar 3,5 Balu,Mano,Stephan
Sno Machines WorkMins Production_kg
--------------------------------------------
1 1 480 800
2 2 300 500
3 3 480 1200
4 4 480 900
5 5 480 1000
and then only Date:04-03-2015 Shift - II, and so on.
If I use sub report concept, for example, I am giving for one day report means, it prints like employee table for all shift and then production table for shift on that day. But I need to print as above.
Can someone give me a solution to overcome this problem?
I think you can use a sub report, I know that you need a HashMap to build a sub report, then I propose the following:
1.- Create three classes:
public class RowEmployee {
private int sno;
private String supervisor;
private int [] machines;
private String [] employees;
// getters and setters
}
public class RowMachinesDetails {
private int sno;
private int machine;
private int workMins;
private int productinKg;
// getters and setters
}
public class Shift {
private Date dateShift;
private List<TableEmployee> listTableEmployee;
private List<TableMachinesDetails> listTableMachinesDetails;
// getters and setters
}
The RowEmployee class is for the first table, the RowMachinesDetails is for the second table and the Shift class is for each shift of your report. As you can see, the Shift class has a list of RowEmployee and a list of RowMachinesDetails, because these lists correspond to each table, also it has a date which corresponds to date of the shift.
2.- Fill your lists with data of employee and data of production
List<TableEmployee> listTableEmployee = new ArrayList<TableEmployee>();
List<TableMachinesDetails> listTableMachinesDetails = new ArrayList<TableMachinesDetails>();
//Create instances of TableEmployee and TableMachinesDetails, and fill your lists
listTableEmployee.add(TableEmployee);
listTableMachinesDetails(TableMachinesDetails);
3.- Create instances of Shift and fill your HashMap with these instances, put the number of shift as key in the HashMap.
//Create instances of Shift
Shift shift = new Shift();
shift.setDateShitf (dateShift);
shift.setListTableEmployee(listTableEmployee);
shift.setListTableMachinesDetails(listTableMachinesDetails);
//Fill the HashMap
hashMapShift.add("I", shift);
4.- Finally, create your datasource as HashMap in iReport and use hashMapShift to fill your datasource.
NOTE: Maybe the type of variables aren't appropiate, the most important is the concept of the solution.
I hope this helps you.
Good Luck.
I'm making a program to make a list of people, with 3 different marks of time (in double)
To do it, I made 4 arrays, One String, to save people names, and 3 Doubles to save the 3 marks on the years 2010, 2011, and 2012.
In the menu, I have to implement an option to sort the list on 2012s mark, in descending order.
Like this
m12[0] = 12.1
m12[1] = 34.1
m12[2] = 23.1
m12[3] = 23.5
into:
m12[1] = 34.1
m12[3] = 23.5
m12[2] = 21.1
m12[0] = 12.1
I did it with a basic algorithm, but now I want to know if it's possible to get the actual order of the arrays, ([1],[3],[2],[0]) and apply it to the other arrays I have to print it as a list based on the 2012 mark in descending order.
Thats the code I have to make the normal order list:
if(option==2){
System.out.println("# , Name, 2010, 2011, 2012");
for(i=0;i<dorsal.length-1;i++){
if(dorsal[i]!=0){
System.out.println(dorsal[i]+"- "+nom[i]+", "+m10[i]+", "+m11[i]+", "+m12[i] );
}
}
System.out.println("Press ENTER to return");
intro.nextLine();
}
Sorry if I didnt explained it very good, I started programming 3 months ago and I'm so newbie.
//EDIT
I'll paste here the head of the exercise:
Thats exactly the programs needs to do. I'm stucked at point 3.
The objective is to develop a program to manage a list of members of
in a competition of long jump. The number of places available is 15.
Their data will be introduced in the same order in which the athletes
enroll. Design a program that shows the following options:
1 – Register a participant
2 – List all the participant’s data
3 – List all the participant’s data by mark
4 – Quit
If 1 is selected, data of one of the participants will be introduced:
Name, best mark in 2012, best mark in 2011 and best mark in 2010.
If 2 is selected, we have to list all participant’s data ordered by dorsal
number (the order they’ve enrolled)
If 3 is selected, we have to list all participant’s data ordered by 2012
mark, from greater to smaller.
After processing each option, the main menu must be shown again,
till the option 4 is selected, quitting the program.
Thanks.
Define a class to contain the data for each person, such as:
public class Person
{
private String name;
Private Map<Integer,Double> marks = new HashMap<Integer,Double>();
public Person(String name) { this.name = name; }
public void setMark(int year, double mark) {
this.marks.put(year,mark);
}
public void getMark(int year) {
// return zero if there's no mark for the requested year
return this.marks.containsKey(year) ? this.marks.get(year) : 0;
}
}
Then write a Comparator<Person>
public PersonComparatorOnMarkDescending implements Comparator<Person>
{
private int yearToCompare;
public PersonComparator(int yearToCompare) {
this.yearToCompare = yearToCompare;
}
public compare(Person p1, Person p2)
{
Integer p1Mark = p1.getMark(yearToCompare);
Integer p2Mark = p2.getMark(yearToCompare);
return p2.compareTo(p1);
}
}
You can then define a List<Person> or a Person[] array and use the sorting methods available in java.util. Instantiate the comparator with, for instance:
Comparator<Person> comp = new PersonComparatorOnMarkDescending(2012);
This approach lets you sort the collection on any year's marks.
Goal: Add a new Movie object to an existing Movie[] if there is room to add.
Code:
// Create the new Movie object
Movie movieToAdd = new Movie (newTitle, newYear);
// Add it to the Array
count = addMovie(movieList, movieToAdd, count);
Method Code:
public static int addMovie (Movie[] movieArray, Movie addMe, int count)
{
if (count != movieArray.length)
{
count++;
movieArray[count] = addMe;
System.out.println("Movie added successfully!");
}
else
{
System.out.println("Array size of " + movieArray.length + " is full. Could not add movie.");
}
return count;
}
QUESTION:
Currently, when the movieList array is printed out, the new entry prints as null even though the created Movie object will print just fine outside of the way. Therefore, I'm assuming the best way to add the addMe object into the array is to create a second new Movie object initialized within the array and build it piece by piece (so addMe will remain in memory, and a "copy" of addMe will be set into the array).
This to me doesn't feel very efficient (I hate extra data laying about...). Is there a better way to do this?
NOTE: The Movie object actually has 10 private data members. For this exercise I only needed to pass in two parameters and set defaults for the rest. You can imagine why I don't to use ten GET statements to build this array and have extra objects stuck in memory...
EDIT:
Current Print Out (Portions):
Menu options:
1. Show all movies:
2. Show movies sorted - manual
3. Show movies sorted - auto
4. Show Movie by Index
5. Search for movie Linearly
6. Search for movie using Binary Search
7. Add a movie
20. Quit
Please choose an option from the menu: 1 to 20:
7
Let's add the information for the new movie. Give me a Title and 4-digit Year, and I'll fill in the rest.
Title?
Me
Year of Release?
Please enter a valid 4 digit year: 1000 to 9999:
1213
Movie added successfully!
Menu options:
1. Show all movies:
2. Show movies sorted - manual
3. Show movies sorted - auto
4. Show Movie by Index
5. Search for movie Linearly
6. Search for movie using Binary Search
7. Add a movie
20. Quit
Please choose an option from the menu: 1 to 20:
25 | Les Vampires (1915) | Louis Feuillade | "Edouard Mathe, Marcel Levesque" | 1915 | 0 | http://www.imdb.com/title/tt0006206/ | http://www.guardian.co.uk/film/movie/117077/vampires | France | Horror | 175
null | 176
=============================================================================
MORE EDITS:
Constructor and Setters code - all this SHOULD be working right though.
public Movie (String t, int y)
{
// passed in
this.title = setTitle(t);
this.year = setYear(y);
// defaults
this.ranking = 0;
this.director = "No Director";
this.actors = "No Actors";
this.oscars = 0;
this.linkIMDB = "No IMDB Link";
this.linkGuardian = "No Guardian Link";
this.country = "No Country";
this.genre = "No Genre";
}
public String setTitle (String newTitle)
{
if (newTitle == null)
{
this.title = "No Title";
}
else
{
this.title = newTitle;
}
return this.title;
}
public int setYear (int newYear)
{
if (newYear >= 999 && newYear <=10000)
{
this.year = newYear;
}
else
{
newYear = 0000;
}
return this.year;
}
It isn't clear what you are asking, but this portion is incorrect:
count++;
movieArray[count] = addMe;
What if movieArray.length is 10, and count is 9? Then it will pass the count != movieArray.length check and then you will try to assign the element at index 10. Use post increment:
movieArray[count++] = addMe;
GOT IT!
I was using Count to set the index at which the new movie was stored.
Original count was 176.
Last index was 175.
I was increment BEFORE setting the movie, so the movie was being set at index 177.
So 176 was getting skipped.
It was only printing to 176 because that was the actual count, which wasn't accounting for the skipped space (there was an extra object in the array that wasn't getting printed).
(Figured this out when I attempted adding 2 new Movie objects to the array and got a null and then the first object only on print).
Solved by switching the set and the increment:
if (count <= movieArray.length)
{
movieArray[count] = addMe;
count++;
System.out.println("Movie added successfully!");
}
i know virtually no java but i'm trying to learn some for this project. I am trying to modify a program called GyaPickupBot which is basically a "pick up game" bot on IRC where players can type: !add in order to get added to a list of players who want to play a game and once enough players !add the bot announces the ip of the game server (i.e. quake server) that the game is to be played on. right now, when the specified number of players !add and the game launches, the bot only lists the players who previously !add'ed before the max number of players was reached. I would like for it to divide all of the players who have !add'ed up into 2 random teams of equal size. I have already done the random part using Collections.shuffle but I have no idea how to divide the players into 2 equally sized teams. I emailed the author who is based in Japan a few weeks ago and he finally replied this morning with some very vague hints on how to do this:
Well... at this time, I don't have much motivation to maintain this code.
I can only suggest you some hints.
private boolean handleReady(String channel, String sender, String login, String hostname, String message) {
boolean isUpdate = false;
String readyGameID = mgr.getReadyGameID();
if (null != readyGameID) {
// *** add some code here to choose teams and store that result to string variable. something like: "team1: ,,,, team2: ,,,,,"
// *** you can get players list by mgr.getPlayers(readyGameID) in order to divide players to 2 teams randomly
for (String ch : getChannels()) {
sendMessage(ch, mgr.getPickupReadyString(readyGameID));
// sendNotice(ch, mgr.getPickupReadyString(readyGameID));
// *** then, send that string to channel
}
mgr.setLastGame(Calendar.getInstance().getTimeInMillis(), mgr.getPickupReadyString(readyGameID));
ArrayList<String> players = mgr.getPlayers(readyGameID);
for (String nick : players) {
sendNotice(nick, mgr.getPickupReadyPMString(readyGameID));
// *** and send that string to players too
}
isUpdate = mgr.clearPlayers(players);
}
return isUpdate;
I know this is probably more than what is asked on here, but I'm really trying to learn this but I can't figure it out and any help would be appreciated
The code below is untested, but should give you an idea on how to proceed. Good luck.
// retrieve all players
ArrayList<String> players = mgr.getPlayers(readyGameID);
// randomize the list
Collections.shuffle(players);
// instantiate two arraylists for the teams
ArrayList<String> teamRed = new ArrayList<String>();
ArrayList<String> teamBlue = new ArrayList<String>();
// add the first half of players to teamRed
teamRed.addAll(players.subList(0, players.size() / 2 + players.size()%2));
// and the second half to teamBlue
teamBlue.addAll(players.subList(players.size() / 2 + players.size()%2, players.size()));
// now do whatever you need to do with the two teams