Priority comparator not working as expected - java

PriorityQueue<StoreEmail> emails = new PriorityQueue<StoreEmail> (n,
new Comparator<StoreEmail> () {
public int compare(StoreEmail a, StoreEmail b) {
if(a.urgency != b.urgency){
return b.urgency - a.urgency;
}
else{
return a.timestamp - b.timestamp;
}
}
}
);
public class StoreEmail
{
String emailContent;
int urgency;
long timestamp;
StoreEmail(String emailContent, int urgency,long timestamp){
this.emailContent = emailContent;
this.urgency = urgency;
this.timestamp = timestamp;
}
}
Inserting in the queue
StoreEmail storeEmail = new StoreEmail(in.next(),in.nextInt(),System.currentTimeMillis());
emails.add(storeEmail);
For above comparator, Inserting following values in the priority queue.
store email value
store email5 4
store email4 4
store email3 4
store email2 4
store email1 4
Its giving different result in each run, it means comparator is not working properly, and not able to sort based on time stamp.
Note: Wanted to sort based on email value maintaining FIFO order.
Can somebody help me how to resolve this problem.
Thanks in advance. Wested a lot of time already.

Related

Sort ArrayList of objects with "pinned" objects at top behaves differently each execution

So I am trying to display a list of groups in a recyclerview in Android.
The groups are custom objects (Group) with a small amount of values, stored in a public static Arraylist (allGroups).
I have a method to sort these groups by their "time" value, which is the time in milliseconds.
Method to sort:
public static ArrayList<Group> sort(ArrayList<Group> list) {
list.sort(Comparator.comparing(Group::getTime));
Collections.reverse(list);
ArrayList<Group> newSort = new ArrayList<>();
for(Group g: list) {
if(g.isPinned()) {
newSort.add(g);
}
}
for(Group g: list) {
if(!g.isPinned()) {
newSort.add(g);
}
}
list.clear();
return newSort;
}
When I run the app the first time, it works fine and sorts my groups perfectly by pin and date, but whenever I add a group using the method below, it ONLY sorts it by date
allGroups.add(new Group(
new BigInteger(130, new java.util.Random()).toString(32),
"PB",
(long) (Math.random() * 1649157582577L),
new BigInteger(260, new java.util.Random()).toString(32)
).makePinned(false));
allGroups = sort(allGroups);
groupsAdapter.notifyDataSetChanged();
I have no clue what might be causing this, it makes no sense to me.
Edit:
Implementation for makePinned:
public Group makePinned(boolean pinned) {
this.pinned = pinned;
return this;
}
Constructor of Group:
public Group(String name, String logo, long time, String message) {
this.id = groupAmount + 1;
this.name = name;
this.logo = logo;
this.time = time;
this.message = message;
}
Your "Found the Answer" is incorrect, because your second sort statement :
list.sort(Comparator.comparing(Group::isPinned));
totally overwrites the first sort. OK, for your test sample, it MIGHT be giving the results you desire (coincidentally preserving some of the order from the first sort), but that is undefined behaviour that is NOT to be relied upon.
What it looks like you might be after is better implemented as :
allGroups.sort(Comparator.comparing(Group::isPinned)
.thenComparing(Group::getTime).reversed());
This is explicitly sorting by isPinned first, and then by getTime in reverse order. Explicit is good.
I have written an example program that is available here : Online Java Compiler, that :
sorts as per your question
Randomises the list (ie, undoes the sorting)
Sorts as above

How to set an array of nested objects that has variable size as source for javafx TableView TableColumns

I have an object of type ClassTestEvaluation. It holds an ArrayList of type Task. This array can have any number of tasks and is not predictable. I want to set up a table view that will show the given tasks in columns so that the user can enter points.
My problem is that I have no idea how to set an array of variable length that is part of another object as source for my table view. I cannot build a wrapper like ClassTestEvaluationItem with simple members task1, task2, etc. since the number of tasks is not fixed. Thus my question is what do I have to do to properly set the propertyValueFactories for the tasks columns?
I have followed lots of tutorials like the one here: https://docs.oracle.com/javafx/2/ui_controls/table-view.htm. It's generally speaking no problem to follow and get them working. But they only deal with simple (flat) data.
TableView<ClassTestEvaluation> table = new TableView<>();
TableColumn colFirstName = new TableColumn("Vorname");
colFirstName.setCellValueFactory(new PropertyValueFactory<ClassTestEvaluation, String>("firstName");
TableColumn colLastName = new TableColumn("Nachname");
colLastName.setCellValueFactory(new PropertyValueFactory<ClassTestEvaluation, String>("lastName");
table.getColumns().addAll(colFirstName, colLastName);
ArrayList<Task> tasks = classTestEvaluation.getTasks();
for(Task t : tasks) {
TableColumn colTask = new TableColumn(t.getTitle());
table.getColumns().add(colTask);
}
As you can see it's not hard to set PropertyValueFactory for colFirstName and colLastName. But how do I do that for the tasks that are variable in
length and are stored in an array which itself is part of the
ClassTestEvaluation object?
Depending on the number of tasks a classtest has got, I want my table view to look like that:
Firstname | Lastname | Task 1 | Task 2 | ...
I hope someone can help me out here since I don't get it. Thanks a lot!
EDIT 1:
To make my data source a bit more clear, here is the relevant structure of my ClassTestEvaluation and Task classes:
public class ClassTestEvaluation{
// ... more members ...
ArrayList<Task> tasks = ArrayList<>();
public ArrayList<Task> getTasks(){
return this.tasks;
}
// ...more methods...
}
public class Task{
private int id;
private int idClassTestEvaluation;
private Double points;
private String title;
public String getTitle(){
return this.title;
}
public Double getPoints(){ // This methods needs to be connected as data source for tasks cells.
return this.points;
}
// ...more methods...
}
The data comes from an sqlite database, where every task is connected via foreign key to a specific ClassTestEvaluation. When necessary a specific ClassTestEvaluation is constructed and gets populated with the corresponding tasks. Thus I need to find a way to make the tasks (i.e. not only their titles as columns, but also their points as cells) available and editable inside the table view.
Well, I actually found the solution to my own question and thought this might be of interest to others. To recall: my problem was that I didn't know how to built columns out of an array of variable length, which is part of another item (composed).
What I needed to understand is how cellValueFactory, cellFactory and onEditCommit can be used togehter with callbacks or lambdas respectivly to get the desired result. This took me quite a while.
Here is what I did to get it:
private void createTableColumnsForTasks(ClassTestEvaluation cte) {
int resultCounter = 1;
// For each given task in ClassTestEvaluation...
for (Task t : cte.getTasks()) {
// ...create a column for the corresponding points reached (0 in the beginning).
TableColumn<ClassTestEvaluationRow, Double> colResult = new TableColumn<>("A" + resultCounter + " (" + t.getPoints() + ")");
resultCounter++;
// Make the column editable.
colResult.setEditable(true);
// Define how the values in the task columns will be set.
colResult.setCellValueFactory((TableColumn.CellDataFeatures<ClassTestEvaluationRow, Double> row) -> {
ClassTestEvaluationRow cter = row.getValue();
for(Result r : cter.getResults()) {
if(r.getIdTask() == t.getId()) {
ObservableValue<Double> obsResult = new SimpleObjectProperty<Double>(r.getPoints());
return obsResult;
}
}
return null;
});
// Create combo box to choose points from for each given task and result.
createTableColumnComboBoxForResultEditing(colResult, t);
// Create method to store edited data in selected ClassTestEvaluationRow.
createOnEditCommitMethods(colResult, t);
((EvaluatorUI) this.getView()).getTableView().getColumns().add(colResult);
}
}
private void createTableColumnComboBoxForResultEditing(TableColumn<ClassTestEvaluationRow, Double> colResult, Task t) {
ArrayList<Double> cbPoints = new ArrayList<>();
for(double i = 0.0; i <= t.getPoints(); i = i+0.5) {
cbPoints.add(i);
}
ObservableList<Double> obsPoints = FXCollections.observableArrayList(cbPoints);
colResult.setCellFactory(ComboBoxTableCell.<ClassTestEvaluationRow, Double>forTableColumn(obsPoints));
}
private void createOnEditCommitMethods(TableColumn<ClassTestEvaluationRow, Double> colResult, Task t) {
colResult.setOnEditCommit((CellEditEvent<ClassTestEvaluationRow, Double> event) -> {
TablePosition<ClassTestEvaluationRow, Double> pos = event.getTablePosition();
Double newValue = event.getNewValue();
int row = pos.getRow();
ClassTestEvaluationRow cter = (ClassTestEvaluationRow) event.getTableView().getItems().get(row);
for(Result result : cter.getResults()) {
if(result.getIdTask() == t.getId()){
result.setPoints(newValue);
classTestEvaluationsService.updateResult(cter.getClassTestEvaluation(), result);
}
}
});
}
I hope this is of help to some of you. Greetings.

Efficiently search a list of consecutive date periods

I have a structure which contains consecutive time periods (without overlap) and a certain value.
class Record {
private TimeWindow timeWindow;
private String value;
}
interface TimeWindow {
LocalDate getBeginDate();
LocalDate getEndDate(); //Can be null
}
My goal is to implement a function which takes a date and figures out the value.
A naive implementation could be to loop through all records until the date matches the window.
class RecordHistory {
private List<Record> history;
public String getValueForDate(LocalDate date) {
for (Record record : history) {
if (record.dateMatchesWindow(date)){
return record.getValue();
}
}
return null; //or something similar
}
}
class Record {
private TimeWindow timeWindow;
private String value;
public boolean dateMatchesWindow(LocalDate subject) {
return !subject.isBefore(timeWindow.getBeginDate()) && (timeWindow.getEndDate() == null || !subject.isAfter(timeWindow.getEndDate()));
}
public String getValue(){
return value;
}
}
The origin of these values are from database queries (no chance to change the structure of the tables). The list of Records could be small or huge, and the dates vary from the start of the history until the end. However, the same date will not be calculated twice for the same RecordHistory. There will be multiple RecordHistory objects, the values represent different attributes.
Is there an efficient way to search this structure?
You can use binary search to get the matching Record (if such a record exists) in O(logn) time.
Java already has data structure that do that for you, e.g. the TreeMap. You can map every Record to its starting time, then get the floorEntry for a given time, and see whether it's a match.
// create map (done only once, of course)
TreeMap<LocalDate, Record> records = new TreeMap<>();
for (Record r : recordList) {
records.put(r.getTimeWindow().getBeginDate(), r);
}
// find record for a given date
public String getValueForDate(LocalDate date) {
Record floor = records.floorEntry(date).getValue();
if (floor.dateMatchesWindow(date)) {
return r;
}
return null;
}
If the entries are non-overlapping, and if the floor entry is not a match, than no other entry will be.

Related jobs in JSprit , One before another case : IllegalArgumentException

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.

Java: counting number of times data appears in a class

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.

Categories

Resources