I know how to count most things when it comes to Java, but this has either stumped me a lot, or my brain is dying. Anyway, I have a class called "Jobs", and within that class is a String variable called "day". Multiple new Jobs have been created already (exact number is unknown), and now I need to query and find out how many Jobs are on x day. I assume it would be easy enough with a while loop, but I don't know how to create one that looks through Jobs as a whole rather than one specific one.
The Job data was created by reading a file (the name of which is jobFile) via a Scanner.
public class Job_16997761 {
private int jobID; // unique job identification number
private int customerID; // unique customer identification number
private String registration; // registration number for vehicle for this job
private String date; // when the job is carried out by mechanic
private String day; // day of the week that job is booked for
private double totalFee; // total price for the Job
private int[] serviceCode; // the service codes to be carried out on the vehicle for the job
//Constructor
public Job_16997761(int jobID, int customerID, String registration,
String date, String day, double totalFee, int[] serviceCode) {
this.jobID = jobID;
this.customerID = customerID;
this.registration = registration;
this.date = date;
this.day = day;
this.totalFee = totalFee;
this.serviceCode = serviceCode;
}
Not sure why you are creating a dynamic instance of a job (eg. Job_16997761, it seems that each job has its own class). But when creating the jobs you can maintain a map that will have the number of jobs per day. Something like:
Map<String, Long> jobsPerDay=new HashMap<String,Long>();
Then when creating a new job you can simply increment the counter for each day:
jobsPerDay.put(day,jobsPerDay.get(day)!=null?jobsPerDay.get(day)++:1);
This way you will be able to get the number of jobs for a day by using: jobsPerDay.get(day)
Please note that you can use java.time.DayOfWeek instead of a String.
It's hard to tell you correct solution unless you give more details. You are saying you can write while loop so I will assume you have a collection of Job already.
int count = 0;
List<Job> jobs = readJobsFromFile();
for(Job job : jobs) {
if(job.getDay().equals(inputDay)){ //inputDay is day you have to find number of jobs on.
count++;
}
}
System.out.Println(count);
This is just one of the many ways and may not be that efficient, but this is one way you may consider (Before you edited your last post). Using an arrayList to contain all the Job objects and iterate through the objects.
import java.util.*;
public class SomeClass {
public static void main(String[] args)
{
Jobs job1 = new Jobs(1);
Jobs job2 = new Jobs(1);
Jobs job3 = new Jobs(2);
Jobs job4 = new Jobs(2);
Jobs job5 = new Jobs(2);
ArrayList<Jobs> jobList = new ArrayList<Jobs>();
jobList.add(job1);
jobList.add(job2);
jobList.add(job3);
jobList.add(job4);
jobList.add(job5);
System.out.println(numOfJobOnDayX(jobList, 2)); //Jobs which falls on day 2
}
public static int numOfJobOnDayX(ArrayList<Jobs> jobList, int specifiedDay)
{
int count=0;
for(int x=0; x<jobList.size(); x++) //May use a for-each loop instead
if(jobList.get(x).days == specifiedDay)
count ++;
return count;
}
}
OUTPUT: 3
Class for Jobs..
class Jobs
{
int days;
public Jobs(int days)
{
this.days = days;
}
}
For simplicity, I am not using any getter and setter methods. You may want to think about what data structure you want to use to hold your objects. Once again, I need to re-emphasize this may not be an efficient way, but it gives you some ideas some possibilities of doing the count.
Related
This question is related to this topic : Related jobs in JSprit
I'm trying to use the "one before another" constraint but i'm experiencing a java.lang.IllegalArgumentException: arg must not be null . It looks like Capacity cap2 is null when calculating Capacity max. I don't really understand why.
:(
Do you have an idea about this?
For the record, I'm on the 1.6.2 version. TY for your help.
String before = "2";
String after = "11";
final StateManager stateManager = new StateManager(problem);
stateManager.addStateUpdater(new JobsInRouteMemorizer(stateManager));
ConstraintManager constraintManager = new ConstraintManager(problem, stateManager);
constraintManager.addConstraint(new OneJobBeforeAnother(stateManager, before, after));
final RewardAndPenaltiesThroughSoftConstraints contrib = new RewardAndPenaltiesThroughSoftConstraints(problem, before, after);
SolutionCostCalculator costCalculator = new SolutionCostCalculator() {
#Override
public double getCosts(VehicleRoutingProblemSolution solution) {
double costs = 0.;
List<VehicleRoute> routes = (List<VehicleRoute>) solution.getRoutes();
for(VehicleRoute route : routes){
costs+=route.getVehicle().getType().getVehicleCostParams().fix;
costs+=stateManager.getRouteState(route, InternalStates.COSTS, Double.class);
costs+=contrib.getCosts(route);
}
return costs;
}
};
VehicleRoutingAlgorithmBuilder vraBuilder = new VehicleRoutingAlgorithmBuilder(problem,
"algorithmConfig.xml");
vraBuilder.addCoreConstraints();
vraBuilder.setStateAndConstraintManager(stateManager, constraintManager);
vraBuilder.addDefaultCostCalculators();
vraBuilder.setObjectiveFunction(costCalculator);
algorithm = vraBuilder.build();
public class JobsInRouteMemorizer implements StateUpdater, ActivityVisitor {
private StateManager stateManager;
private VehicleRoute route;
public JobsInRouteMemorizer(StateManager stateManager) {
super();
this.stateManager = stateManager;
}
#Override
public void begin(VehicleRoute route) {
this.route=route;
}
#Override
public void visit(TourActivity activity) {
if(activity instanceof JobActivity){
String jobId = ((JobActivity) activity).getJob().getId();
StateId stateId = stateManager.createStateId(jobId);
System.out.println(stateId.getIndex());
System.out.println(stateId.toString());
stateManager.putProblemState(stateId, VehicleRoute.class, this.route);
}
}
#Override
public void finish() {}
}
Short answer: You cannot create StateId instances on the fly. All StateId instances have to be generated before the algorithm is run. See longer answer for why doing this is still not a good idea and you should consider a redesign.
Analysis: I ran into the same problem and traced it back to the way StateId instances are created in StateManager:
public StateId createStateId(String name) {
if (createdStateIds.containsKey(name)) return createdStateIds.get(name);
if (stateIndexCounter >= activityStates[0].length) {
activityStates = new Object[vrp.getNuActivities() + 1][stateIndexCounter + 1];
vehicleDependentActivityStates = new Object[nuActivities][nuVehicleTypeKeys][stateIndexCounter + 1];
routeStatesArr = new Object[vrp.getNuActivities()+1][stateIndexCounter+1];
vehicleDependentRouteStatesArr = new Object[nuActivities][nuVehicleTypeKeys][stateIndexCounter+1];
problemStates = new Object[stateIndexCounter+1];
}
StateId id = StateFactory.createId(name, stateIndexCounter);
incStateIndexCounter();
createdStateIds.put(name, id);
return id;
}
Each time you create a new StateId and there is no more space available for states the old state arrays are overwritten with a longer version to make space for your new state (at start there is space for 30 StateIds, a few already used by JSprit itself). As you can see, the old elements aren't copied over, so what happens here is a race condition between UpdateLoads, which sets the state used as cap2, your code, which generates a new StateId and overwrites the current state and UpdateMaxCapacityUtilisationAtActivitiesByLookingForwardInRoute which reads the state (that doesn't exist anymore).
Given that this code only extends the arrays by one it is very inefficient to have many StateIds, as for each new StateId all arrays have to be recreated. To mitigate this I used only one StateId in my code and stored a Map<String, VehicleRoute> in it:
Map<String, VehicleRoute> routeMapping = Optional.ofNullable(stateManager.getProblemState(stateId, Map.class)).orElse(new ConcurrentHashMap<>())
This way you don't run out of StateId instances and can still store relations between an unlimited number of jobs.
What I have below is producing the desired results by print some employee details along with weekly / monthly wages as appropriate.
However I understand that I should not be inputting data in the constructor as I've done.
I need to prompt for a hours worked value only for "PartTimeEmployees", just not the way I've done it.
I've tested with For-Each loops, Enhanced For loops and using the instanceOf operator.
If I could get some guidance/hints or examples of how to accomplish what is currently being done in the constructor, but in the TestEmployee class instead that would be great.
Mostly I'm not sure how to even describe what I'm trying to achieve. This hinders Googling somewhat. (Help with a better title would also be great)
Thanks in advance.
public class TestEmployee
{
public static void main(String[] args)
{
int size;
Employee[] employees = new Employee[4];
employees[0] = new FullTimeEmployee("Jane", 26000);
employees[1] = new PartTimeEmployee("Jack");
employees[2] = new FullTimeEmployee("Lucy", 52000);
employees[3] = new PartTimeEmployee("Lenny");
for(int i = 0; i < employees.length; i++)
{
employees[i].print();
}
}
}
Class: PartTimeEmployee - Constructor:
public PartTimeEmployee(String thisName)
{
super(thisName);
System.out.println("Please enter the number of hours worked by " + thisName + ": ");
numHours = keyboard.nextInt();
setHours(numHours);
}
If I get your question, below might fit with your need -
First of all create generic Employee class -
class Employee {
private String name;
private int workingHours;
private final boolean IS_PART_TIME_EMP;
public Employee(String name, int workingHours) {
this.name = name;
this.workingHours = workingHours;
this.IS_PART_TIME_EMP = false;
}
public Employee(String name) {
this.name = name;
this.IS_PART_TIME_EMP = true;
}
public String getName() {
return name;
}
public int getWorkingHours() {
return workingHours;
}
public void setWorkingHours(int workingHours) {
this.workingHours = workingHours;
}
public boolean isPartTimeEmployee() {
return IS_PART_TIME_EMP;
}
}
Now you can use it as per your requirement.
Employee[] employees = new Employee[4];
employees[0] = new Employee("Jane", 26000);
employees[1] = new Employee("Jack");
employees[2] = new Employee("Lucy", 52000);
employees[3] = new Employee("Lenny");
Scanner sc = new Scanner(System.in);
for (Employee employee : employees) {
if(employee.isPartTimeEmployee()) {
System.out.println("Please enter working hours by " + employee.getName() + ": ");
int numHours = sc.nextInt();
employee.setWorkingHours(numHours);
}
}
Constructor is not meant for user input.Its main intention is to initialize object of that class.
Instead of doing that in constructor,you can try something like this
employees[1] = new PartTimeEmployee("Jack");
System.out.println("Please enter the number of hours worked by " + employees[1].getName()+ ": ");
numHours = keyboard.nextInt();
employees[1].setHours(numHours);
You most likely will have some logical main loop in your program, like
while(!quit) {
// 1. ask if you want to add part time or full time employee
// 2. ask proper questions
// 3. call correct constructor
}
Writing such small pseudo code algorithm should be self explanatory and get you going.
Step one: presentation of options available for user and reading user input.
Step two: performing actions depending on user input from step 1
Step three: final call to proper constructor depending on results from steps 1 and 2
If I understood your question correctly (which I'm really not sure of) you want to prompt for the employee data in the main method.
In that case I'd use a loop and query the following things:
name of the employee
does the employee work full time? (y/n)
if yes: what is the wage? (assume hours = whatever a full time employee works a day)
if no: how many hours? (and probably the hourly wage as well)
Then use that information to construct an Employee object (I don't see any need for the subclasses here).
I am sending prices to customers (10000+) but below code has loop that causes delays in the process for customers waiting for calculations.
PriceVisibleForCustomer = Price + CustomerMargin
Price - changing every 300ms - sent from central store, not related to customer instance
CustomerMargn - some plus or minus amount that is resulting from customer agreement/segment/administrator decision etc. It doesnt change during customer http session, I can keep it in memory
Customer - he takes part in the process after he logs in, he should see rapidly changing prices of 8 products.
Maybe I need some more technology ? I have Spring 3/4, Java, Weblogic and i could create even separate webapp for this task for providing calculated prices.
I thought about threads in Java but 10000+ customers would mean too many threads wouldnt it ? How to change this code? Maybe I should change architecture but how?
/**
* Sends prices to customer. This method is called very often (300ms) as prices are changing in real time.
* Customer should see prices also each 300ms
* #param productId - id of a product that prices will be calculated
* #param productIdToPriceMap
* #param customerIdToMarginMap - this map is changed every time customer logs in or logs out
*/
private static void sendPricesToCustomers(Long productId,
Map<Long, BigDecimal> productIdToPriceMap,
Map<Long, BigDecimal> customerIdToMarginMap) {
//This loop is blocking last customer from receiving price until all other customers wil have theri prices calculated. I could create threads, 10000+ customers will be logged in, I cant create so much threads... can I?
for (Long customerId: customerIdToMarginMap.keySet()){
BigDecimal customerMargin = customerIdToMarginMap.get(customerId);
BigDecimal priceResult = productIdToPriceMap.get(productId).add(customerMargin);
//send priceResult to websocket
}
}
Here is a simple example of the Listener pattern, I am not sure if this approach will work for you but just throwing out some ideas ...
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.swing.Timer;
public class Demo {
public static Product[] PRODUCTS = new Product[]{
new Product("Computer", 400),
new Product("Desk", 800),
new Product("Chair", 70),
new Product("Printer", 300),
new Product("Television", 200)
};
public static void main(String[] args) throws InterruptedException {
Customer john = new Customer("John", 3);
john.addProduct(PRODUCTS[1]);
john.addProduct(PRODUCTS[2]);
john.addProduct(PRODUCTS[3]);
Customer mary = new Customer("Mary", 2);
mary.addProduct(PRODUCTS[1]);
mary.addProduct(PRODUCTS[2]);
mary.addProduct(PRODUCTS[4]);
Thread.sleep(10000);
System.exit(0);
}
}
interface IPriceListener {
public void priceChanged(Product product, int price);
}
class Customer implements IPriceListener {
String _name;
int _margin;
Vector<Product> _products = new Vector<Product>();
public Customer(String name, int margin){
_name = name;
_margin = margin;
}
public void addProduct(Product product){
_products.add(product);
product.addListener(this);
}
public void priceChanged(Product product, int price) {
System.out.println("[" + _name + "][" + _products.get(_products.indexOf(product)).getName() + "][" + price + "][" + (price + _margin) + "]");
}
}
class Product implements ActionListener {
private int _startingPrice;
private int _currentPrice;
private String _name;
private Timer _timer;
private Vector<IPriceListener> _listeners = new Vector<IPriceListener>();
public Product(String name, int price) {
_name = name;
_startingPrice = _currentPrice = price;
_timer = new Timer(300, this);
_timer.start();
}
public void addListener(IPriceListener listener) {
_listeners.add(listener);
}
public void removeListener(IPriceListener listener){
_listeners.remove(listener);
}
private void notifyListeners() {
for(IPriceListener listener : _listeners){
listener.priceChanged(this, getCurrentPrice());
}
}
public void actionPerformed(ActionEvent e) {
_currentPrice = _startingPrice + (int)(Math.random() * (5 - (-5))) + (-5);
notifyListeners();
}
public final String getName() {
return _name;
}
private synchronized final int getCurrentPrice() {
return _currentPrice;
}
}
One way to handle this is to create a single thread whose job is to consume priceResults off a queue and send them down the websocket (I'm assuming you have only one websocket). Your loop would then push priceResults onto the queue every 300ms without blocking the websocket thread. See ConcurrentLinkedQueue javadoc.
Edit:
To avoid the delay between finishing the current loop through customerIdToMarginMap and beginning to loop through the next update, here are some options:
Keep the queue concept and create a fixed thread pool where each thread pulls the next customerId/productIdToPriceMap/customerIdToMarginMapoff the queue. If you have four threads and 10,000 records, each thread will only have to process 2,500 records, thereby starting on the next 300ms data push 4 times earlier than your current implementation. Increase thread count as you find necessary for performance.
Keep my original queue concept but change the way you receive the price updates. The reason you need to loop is because you're getting pricing updates for every customer at the same time. If you can instead e.g. create a threaded listener for a group of customers that receives a customerIdToMarginMap containing only customerIds it's meant to handle, the iteration time will be significantly decreased.
For a given task, I should store an object while keeping track of the time of its creation at least per day.
The easiest solution I could find is to use Calendar to set day of year based on time stamp of objects creation.
Here is the object in a simple form:
public class PhysicalActivity implements Serializable {
private long mTimestamp;
private int mYear;
private int mMonthOfYear;
private int mWeekOfYear;
private int mWeekOfMonth;
private int mDayOfYear;
private int mDayOfMonth;
private int mDayOfWeek;
public PhysicalActivity(long timestamp){
mTimestamp = timestamp;
Calendar c = Calendar.getInstance();
c.setTimeInMillis(mTimestamp);
c.setTimeZone(TimeZone.getDefault());
mYear = c.get(Calendar.YEAR);
mMonthOfYear = c.get(Calendar.MONTH);
mWeekOfYear = c.get(Calendar.WEEK_OF_YEAR);
mWeekOfMonth = c.get(Calendar.WEEK_OF_MONTH);
mDayOfYear = c.get(Calendar.DAY_OF_YEAR);
mDayOfMonth = c.get(Calendar.DAY_OF_MONTH);
mDayOfWeek = c.get(Calendar.DAY_OF_WEEK);
}
//Getters for all members...
}
Then I have this object that holds all instances in an List<PhysicalActivity>:
public class PhysicalActivityHolder implements Serializable {
private long mCreationTimestamp;
private long mLastUpdateTimestamp;
private List<PhysicalActivity> mList;
public PhysicalActivityHolder(long creationTimestamp) {
mCreationTimestamp = creationTimestamp;
if(mList == null) {
mList = new ArrayList<PhysicalActivity>();
}
}
public void addPhysicalActivity(PhysicalActivity pa){
if(mList == null) {
throw new NullPointerException("List is null");
} else {
mList.add(pa);
}
}
public List<PhysicalActivity> getPhysicalActivitiesForDayOfYear(int dayOfYear) {
List<PhysicalActivity> activities = null;
for(PhysicalActivity p : mList) {
if(p.getDayOfYear() == dayOfYear){
activities.add(p);
}
}
return activities;
}
//Some similar methods for getting list by month of year, week of year...etc...
}
Then whenever there is a new PhysicalActivity instance is coming, I read the PhysicalACtivityHolder from disk (deserialize), add the new instance to the List<> and then save (serialize) the Holder object again to the disk.
I hope that you got my point by now. I am afraid this is not going to be a good solution. one of the problems is what if the device's timestamps changes? then the whole idea will be ruined.
I would love to know how would you implement such task? what could be the better way of doing this?
First of all, while not related to the timestamp issue, an SQLite Database would seem like a much more appropriate medium to store this information. In particular:
You don't need to serialize and deserialize the whole collection every time.
You don't need to keep the whole collection in memory.
You can add, remove, or update single events.
You can easily query by year, month, &c using SQL SELECT statements.
About the "timestamp changing" part (unless you have an external, trusted data source for the time, such as a server), yes, the device's date or time may be manually changed. However, how big of a problem would that be? This data wouldn't seem to be critically dependent on having the exact time.
I have two java classes. Schedule is the main class that uses an array of Jobs called deadline. I'm having problems putting anything in array. I have a for loop that reads data from a text file (it works fine) and inserts certain data into deadline. I not successfully creating deadline because whenever I want to start inserting into the array I get a NullPointerException. (The code below the ... obviously isn't what I actually coded, but it is still the same situation.)
It has been a while since I've coded in Java, so I might be just overlooking something simple, but I'm not really sure what it could be... Thanks for any help you can give.
public class Schedule {
private Job []deadline;
Schedule (int n){
Job[] deadline = new Job[n];
}
...
int n = 7;
Schedule schedule = new Schedule(n);
deadline[0] = new Job("A",3,40); // This line won't compile. NullPointerException
}
public class Job {
private String name;
private int deadline;
private int profit;
Job(String n, int d, int p){
name = n;
deadline = d;
profit = p;
}
}
You are shadowing deadline in your constructor, so you don't initialize the class member deadline, but the local one. Change it to:
private Job []deadline;
Schedule (int n){
deadline = new Job[n];
// ^^ note - no Job[] here
}