Java Map<String,Map<String,Integer> use to populate results - java

I want to create one report that you select product and storeName and returns all the sales per date (within a range).
The db view that helped me with other reports looks like this:
product - store_name - date
So far my approach is to return all records from the db in a list and then I do the following:
public void salesReport(String product, String store, String date){
List<RecordSalesInfo> salesResults = salesDao.getSales();
Map<String, Integer> mapper = new HashMap();
//calculation
for (RecordSalesInfo record : salesResults) {
StringBuilder key = new StringBuilder();
key.append(record.getProduct()).append(":")
.append(record.getStoreName()).append(":")
.append(record.getWageredDate()).append(":");
if (mapper.containsKey(key.toString())) {
Integer get = mapper.get(key.toString());
get++;
mapper.put(key.toString(), get);
} else {
mapper.put(key.toString(), 1);
}
}
for (String key : mapper.keySet()) {
if(key.toString.equals("Pen:London:13June2016"){
System.out.println("sales:" + mapper.get(key.toString);
}
}
}
the query in the salesDao(saving as "RecordSalesInfo") is:
SELECT
rs.product AS product,
rs.store_name AS store,
rs.date AS date,
rs.product_id AS productId
FROM sales rs
ORDER BY rs.product,rs.store_name,rs.date
The reason I didn't query "Count(blabla) where product='a' and store_name='b' and date='c' " is because the user changes the input using a jSlider very often (input=product,store,date), that means too many queries. So I thought it is better to take all the results from db and then display what the user needs.
A) Is there a better way to do this?
B) In the next phase the user will enter only the product and the store and I have to return the list of the sales by date, looking like this:
Pen - London (manual input)
12June2016 100
15June2016 30
19July2016 67
With what I have done so far, I can't get only the dates that I have sales, and I have to "search" from the hashMap for all dates(specific range). I think as a solution to change the key to "product:storeName" one the existing map and have as a value another map where the String will be the date and the Integer the amount of sales.
Again is there a better way on doing that?

What I would do is that I will not hold/keep a map, rather I will fetch the results as the query changes based on the JSlider etc.
You can do one thing that when a query is sent until its results are available you can disable your Jslider and show a spinner that notifies the user that processing is going on.
Once the result is available, enable the slider and hide the spinner.
To have all the data in the map does not seem a good idea. It will be a disconnected state of data.

Related

Take records from set and count how many records for each player id

I'm making a leaderboard in my game and I have tiles with certain player ids assigned to them.
I need to take the following data (which is a set containing my 'Tile' records):
[Tile[id=eeebeaa4e03c8910e5c17925439f1fa1abb,position=Vec[x=-11.0, y=6.0, z=73.0], player_id=1oyr8l], Tile[id=3c10969e83a61f44139d5dbeb8b41c9e,position=Vec[x=-12.0, y=6.0, z=73.0], player_id=1oyr8l], Tile[id=f51fd6f3eb407305a49bde1cb2cf44fe,position=Vec[x=-12.0, y=6.0, z=74.0], player_id=qX9Bh7]]
I want to format it into something like:
1oyr8l: 2
qX9Bh7: 1
Or in code form:
public record Tile(String id, Vec position, String owner) {
// irrelevant code here
}
private final Set<Tile> userTiles = getTiles() // dummy func but you get the idea
I want to take userTiles, which is a Set<Tile> and make it into the sorted & counted format I showed above in text format, but in the form of a HashMap, such as:
HashMap<String,Integer> leaderboard = new HashMap<String,Integer>();
Iterate over your Tiles. for(Tile t : getTiles())
Extract the player ID. String playerId = t.player_id()
Check if the player ID exists in the HashMap. if leaderboard.containsKey(playerId)
If it does, increment the value for that key.
If not, add the map with a value of 1.

Find number of workers active on average any time during time range

TLDR: Looking to get the average number of workers (at any time) for each distinct group for a time range using the below SQL table. Either by using a SQL query or in moving the raw data from SQL to java and calculating it there.
I am trying to find the average number of workers in a group (for every group) that are available at any time within a particualar time range (let's say 8/5/2019-9/4/2019) with the given table below:
CREATE TABLE workers(
group VARCHAR(75) NOT NULL,
worker_name VARCHAR(75) NOT NULL,
times tstzrange NOT NULL,
);
To help clarify how the table works a bit: it is meant to represent worker machines that belong to specific groups of workers. I know that a worker has left the group when there is an end bound on the times field which is a tstzrange, otherwise if the worker is still in the group times is unbounded. A worker can be active for any length of time and “times” can span multiple days. A new row is only added when the worker is restarted, or a brand new worker is added. Workers can remain active between days and no new row is created for each day.
One problem that makes this more difficult is that workers may be added to and from the group throughout the course of single day, and sometimes are in for an hour or less. For example there may be 100-120 worker rows for a time range even though the average number of workers for any time in the time range (what I'm looking for) should be 4. Additionally I want the average for every single distinct group. Currently I'm using the query below to get the data, map it to objects in Java and then construct a solution from there.
select worker_name, lower(times) as start, upper(times) as end, group
from workers
where times && tstzrange('2019-08-05', '2019-09-04')
Most of the work is done in Java where I am making a map of each group -> all of the workers that belong to the group and their timestamps. I then am consolidating this list by seeing how many workers are active on each day during the period, and then averaging that over the entire timerange to find the average number of workers that are available in each group for the time period. It seems like this is a bit inefficient and not working as expected for all groups though, and I was wondering if I would be able to do this a better way directly in SQL (or efficiently in java). I've been working on the problem for a little while, and thought it seemed straight forward at first but am struggling to come up with a better solution. Hopefully someone with more experience doing this sort of thing can advise me on a good solution to this problem, and whether this should be handled directly in SQL or if some java logic is needed.
This is what I am using the map the data when I get it from SQL in Java to an object
public class WorkerMapping {
private String group;
private List<LocalDate> dates;
public WorkerMapping(OffsetDateTime start, OffSetDateTime end, String group) {
this.dates = start.toLocalDate().datesUntil(end.toLocalDate()).collect(Collectors.toList());
this.group = group;
}
// Getters and Setters
}
This is what I am using as a key for a HashMap. This allows each key and a date that it active to be a key in the map, which was helpful for summing up the occurences of each group on each day.
public class DateGroupKey {
private String group;
private LocalDate date;
public DateGroupKey(String group, LocalDate date) {
this.group = group;
this.date = date;
}
// Override equals and hash to be used as key for HashMap
}
Current logic to get average for each group:
public HashMap<String, Double> getAverage(List<WorkerMapping> rows)
{
HashMap<String, Double> workerAverage = new HashMap<>();
// Treemap is used so keys can be processed in order, and all groups are together.
TreeMap<DateGroupKey, Integer> map = new TreeMap<>((a, b) -> a.getGroup().equals(b.getGroup()) ?
a.getDate().compareTo(b.getDate()) : a.getGroup().compareTo(b.getGroup()));
for (HostsRow row : rows)
{
for (LocalDate date : row.getDates()) {
DateGroupKey key = new DateGroupKey(row.getGroup(), date);
if (map.containsKey(key)) {
map.put(key, map.get(key) + 1);
} else {
map.put(key, 1);
}
}
}
List<DateGroupKey> keys = new ArrayList<>(map.keySet());
String currentGroup = keys.get(0).getGroup();
int currentSum = 0;
for (DateGroupKey key : keys ) {
if (!key.getGroup().equals(currentGroup)) {
workerAverage.put(currentGroup, Math.ceil(currentSum / 30.0));
currentGroup = key.getGroup();
currentSum = 0;
}
currentSum += map.get(key);
}
workerAverage.put(currentGroup, Math.ceil(currentSum / 30.0));
return workerAverage;
}
I am looking to receive a map of group to average workers for any time during a time range, either by using a better sql query or more efficient java.

Querying mysql with java with multiple possible "where" statements

I'm trying to find a nice solution to a movie filtering system built in java and with a mysql database. The user is supposed to be able to filter which movies they wish to see based on a number of attributes, such as: director, actor, length, genre, year,...,. In total there are 11 fields which can be used to filter the query.
The problem is some of these fields can (and probably will) be left blank. For instance, maybe the user only wants to filter data based on a certain genre, director and length. Or maybe they only want to filter it based on the prodution studio, and dont care about the other filter options.
I have made a connection to the server, and the problem is in creating the "SQL_String" that I will use in statement.executeQuery(SQL_String).
Lets say I only wanted to filter for one field. Then I know I could write
String field = //user input (for example: actor)
String filter = //user input (for example: 'tom cruise')
String SQL_String = "SELECT * FROM Movies WHERE "+field + "=" +filter
But if i want to allow the user to filter based on several (or zero) fields, then I dont know how to write the code.
Some example queries could be:
"SELECT * FROM Movies WHERE (director = 'steven spielberg' AND genre = 'action' AND length >100)"
"SELECT * FROM Movies WHERE (type = 'tv-series' AND actor = 'bob odenkirk')"
So the user can specify which fields they want to filter (if any) and i need to come up with a java code that can take those into account and construct a query string.
Since you don't know how many fields the user will filter on but you do know that the data you're dealing with has two parts (the field and the filter), the first two things that come to my mind are maps and tuples. Since, unlike Python, Java does not have a built in tuple data type (to my knowledge), here is a small example solution that I thought of for your problem solved using Java's HashMap and Map classes.
In this example, I create a HashMap with the key being a string for the "field" and the value being a string for the "filter". You can set these values based on the user input wherever you have that in your code (in this example, simply hard-coded in the main method). Then you can loop through the key-value pairs in your HashMap (see this helpful post), appending the key and value as well as the additional characters necessary for the query. This is a simple example but shows a possible solution route.
If you want to make sure that this solution works for the cases where you filter value is an integer, then just add in another if-statement in the loop to try parsing for an integer and if one exists to not add the extra \' escape characters.
import java.util.HashMap;
import java.util.Map;
public class MovieQueryTest {
public static void main(String[] args) {
String SQL_Query = "SELECT * FROM Movies WHERE ";
HashMap<String, String> queryFilters = new HashMap<>();
queryFilters.put("director", "Steven Spielberg");
queryFilters.put("type", "tv-series");
queryFilters.put("actor", "Bob Odenkirk");
boolean firstQueryFilter = true;
for (Map.Entry<String, String> entry : queryFilters.entrySet()) {
if (firstQueryFilter) {
SQL_Query += entry.getKey() + "=\'" + entry.getValue() + "\'";
firstQueryFilter = false;
} else {
SQL_Query += " AND " + entry.getKey() + "=\'" + entry.getValue() + "\'";
}
}
System.out.println(SQL_Query);
}
}

Stuck on the diagnosis part of my android application

I need an advise on the best approach to complete this task in my android app:
I am working on an android app and got stuck on how to calculate the diagnosis of the patient.
The user (doctor) will perform physical tests on the patient
The user records the value of each physical test <= this data is stored in a shared pref object
i.e- when the user performs an empty can test (physical test), the user will record if the test is positive (1) or negative (0) <= Boolean value (for simplicity, I am using only 4 tests)
The application is supposed to compare the patient findings to the conditions that I want to just hard code in my app (for simplicity, I am using only 8 conditions to compare) then display the condition that the patient would most likely have
--> I am storing the physical test, performed on the patient, results in a shared preference object but do not know how to go from there to come up with the diagnosis (I am looking for a simple approach to make this work)
*** I saved the values from my shared preference object into one dimensional array as below:
// User SharedPreferences to save the value per special id
SharedPreferences sharedPref = getSharedPreferences("STData", Context.MODE_PRIVATE);
Map<String, String> map = (Map<String, String>) sharedPref.getAll();
int[] PTFindings = new int[map.size()];
int index = 0;
if(!map.isEmpty()){
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry entry = (Map.Entry)iterator.next();
PTFindings[index] = (int) entry.getValue();
}
}
**** How should I hard code few conditions to proceed? -> assuming the results of the physical tests of those conditions (positive (1) or negative (0)) do not change
*** I need to compare their values to the one I saved from shared preference then display the most likely diagnosis
Any suggestion would be greatly appreciated
As far as I could understando from your question, you just need a cascading condition.
if(boolean1){
if(boolean2){
//something boolean2 related
} else {
if(boolean3){
etc...
}
}
} else {
//something boolean1 related
}

groovy script / java code to get distinct users from resultset

Hi I run a simple select query in oracle over a table and get a resultset. like select username, responsibility, project from mytable.
The resultset contains user details. there are multiple rows returned for each username with different values for responsibility and project.
Now I want to get a list of lists from this resultset which has one List per username and distinct values are concatenated in a comma seperated string.
So if Sam has multiple entries in the resultset then the output of my operation should give me:
UserList =
["Sam", "responsibility1,responsibility2,responsibility3...", "dept1,dept2,dept3.."],
[Some other User],
[and so on..]
Later I will write this to a csv file.
I cannot do this in the query itself for compatibility reasons, we have to support multiple databases, versions in future.
How do I do this in java or groovy?
Thanks
Java is quite easy.
You need a class to model each user.
You need a Map of username to User.
Each User contains a List of responsibility and a List of departments.
Then you iterate your resultset, find the User from the map on each row and add the responsibility and department to that User
Do you need the code or is that good enough?
HTH
Edit: Here's some Java starting code:
(Not checked for syntax or mistakes ;] )
public class User {
private final List<String> responsibility = new ArrayList<String>();
private final List<String> department = new ArrayList<String>();
...standard getters and setters
}
// Your code to do the read
public void executeRead() {
... obtain the resultset somehow here
Map<String, User> usernameToUser = new HashMap<String, User>():
while (rs.next) {
String username = rs.getString("username");
User user = usernameToUser.get(username);
if (user == null) {
user = new User(); // Create and remember a user the first time you see them
usernameToUser.put(username, user);
}
String responsiblity = rs.getString("responsiblity");
String department = rs.getString("department");
user.addResponsibility(responsibility);
user.addDepartment(department);
}
rs.close();
// Now you have the data structure of users in memory you can output
// it in whichever format you like e.g. HTML, CSV, etc
// Probably best to do this step in a totally separate place that can
// be switched out for a different output format in future.
}

Categories