Java Using a for loop to print calendar (logic help) - java

I have this assignment due by the end of the month and I'm already halfway done. We had to use Zeller's congruence to calculate the day of the week that the 1st landed on. From that point (and accounting for leap years), you have to print off a calendar of the corresponding year using loops. The teacher said that this should be a really short program and we should not try to brute force the the logic of the program (basically, don' t use a bunch of if else and loops for each month). I already have the math calculations and leap year part down, but I can't wrap my head around how to make this for loop work for numerous reasons:
How would I go about factoring in whitespaces for each month? Like how many nested loops will I actually need?
Would I need to write different loops for Leap years, months with 31 days, and months with 30 days, etc or can all this be handled with 1 giant nested loop?
For example, I just started off writing a for loop just to see if I could print off a typical 31 day calendar without any special formatting (whitespaces, Month name, days etc). Here was my first test at using a for loop:
for(int i = 1; i < 31; i++)
{
for(int j = 0; j < 7; j++)
{
System.out.print(i + "\t");
i++;
if(j == 6){
i--;}
if(i > 31)
{
break;
}
}
System.out.print("\n");
}
What is the logic behind using it for multiple months and whitespaces. I welcome all help, but please DO NOT GIVE ME SOURCE CODE. I want the satisfaction of getting this done with code I've written, and like I said, this is also an assignment and I won't really learn from copying and pasting code. Just throw me a bone about the logic I need to use. I can work in all other conditionals for special cases. Thanks guys.

Ok, you need to manage something which varies between a fixed set of values, so you basically need a way to access these variable data from within a loop.
The best tool to fullfil this problem is probably an array.
If you store inside an array, for example the duration of the months you will be able to access them in a straightforward way (through an index) so that you won't need any conditional chain, you will just need the index of the current month, eg monthDurations[i] == 31.
If you want to structure everything better you could define your own Month class or Day class or whatever you need to keep track of printing issues (eg white spaces or names) so that everything will be easily encapsulated and maintainable.

I would write a function to display one month with parameters: dayOfWeek, numberOfDays, [name, firstDayOfWeek]
dayOfWeek - what day of week is 1st day of the month
numberOfDays - number of days in this month
optional parameters You may implement if You like
name - name of the month
firstDayOfWeek - some calendars use Sundays other use Mondays as first day, if You like to have this flexibility You can implement this as well.
And the logic is simple You can do with just one loop that would iterate numberOfDays+dayOfWeek-1 times.
Inside You just need to check for end of week to make new lines and display empty spaces dayOfWeek-1 times in first week.

Related

How to penalize gaps between days in OptaPlanner constraint stream?

I have a model where each Course has a list of available TimeSlots from which one TimeSlot gets selected by OptaPlanner. Each TimeSlot has a dayOfWeek property. The weeks are numbered from 1 starting with Monday.
Let's say the TimeSlots are allocated such that they occupy days 1, 3, and 5. This should be penalized by 2 since there's one free day between Monday and Wednesday, and one free day between Wednesday and Friday. By using groupBy(course -> course.getSelectedTimeslot().getDayOfWeek().getValue()), we can get a list of occupied days.
One idea is to use a collector like sum(), for example, and write something like sum((day1, day2) -> day2 - day1 - 1), but sum(), of course, works with only one argument. But generally, maybe this could be done by using a custom constraint collector, however, I do not know whether these collectors can perform such a specific action.
Another idea is that instead of summing up the differences directly, we could simply map each consecutive pair of days (assuming they're ordered) to the difference with the upcoming one. Penalization with the weight of value would then perform the summing for us. For example, 1, 4, 5 would map onto 2, 0, and we could then penalize for each item with the weight of its value.
If I had the weeks in an array, the code would look like this:
public static int penalize(int[] weeks) {
Arrays.sort(weeks);
int sumOfDifferences = 0;
for (int i = 1; i < weeks.length; i++) {
sumOfDifferences += weeks[i] - weeks[i - 1] - 1;
}
return sumOfDifferences;
}
How can we perform penalization of gaps between days using constraint collectors?
An approach using a constraint collector is certainly possible, see ExperimentalCollectors in optaplanner-examples module, and its use in the Nurse Rostering example.
However, for this case, I think that would be an overkill. Instead, think about "two days with a gap inbetween" as "two days at least 1 day apart, with no day inbetween". Once you reformulate your problem like that, ifNotExists(...) is your friend.
forEachUniquePair(Timeslot.class,
Joiner.greaterThan(slot -> slot.dayOfWeek + 1))
.ifNotExists(Timeslot.class,
Joiners.lessThan((slot1, slot2) -> slot1.dayOfWeek, TimeSlot::dayOfWeek),
Joiners.greaterThan((slot1, slot2) -> slot2.dayOfWeek, TimeSlot::dayOfWeek))
...
Obviously this is just pseudo-code, you will have to adapt it to your particular situation, but it should give you an idea for how to approach the problem.

Java MOOC 92.3 ( I want to understand how to solve this question, not just be provided an answer)

This exercise is from Java MOOC 92.3
Simply, I have two dates.
And a method which gives me the difference of the two.
(for instance: 3/10/2011 and 3/9/2012)
My method states that as long as the month and the day are greater than the later, then simply subtract the one for which the method is called.
Here's the problem:
If a date given as a parameter has a greater year, then when I subtract the two I come out with a negative number (ex: 2011 - 2012).
public int differenceInYears(MyDate comparedDate){
int result = 0;
if(this.month >= comparedDate.month && this.day >= comparedDate.day){
result = this.year - comparedDate.year;
}else{
result = this.year - comparedDate.year;
result--;
}
return result;
The code beyond the else is for the case in which the year is not what it may look to be (Example: If I was born in May 2000 and I technically should be 20 since it is 2020, but since it is not May yet, I am therefore 19).
My conditions are still met within the first if statement, even though the result is not correct. I have tried finding a case where I can appease both cases where it does not matter what date goes first, but I am struggling with the logic. Would appreciate input.
First, if I understand correctly that this is an exercise, it’s a fine exercise. For production work one would never invent their own date class but would and should use LocalDate from the standard library for a date. And ChronoUnit.YEARS.between() for finding your age.
If you have not yet had your birthday this year, you want to subtract one year from the result. This is correct. So how do we determine whether this year’s birthday is in the future? Take a look at the following possibilities. I have not run your code, so have filled out the last column from what I think will happen from reading the code.
Today Birthday Subtract 1? Does your code subtract 1?
--------------------------------------------------------
Apr 3 Feb 1 No No
Apr 3 Feb 6 No Yes
Apr 3 Apr 1 No No
Apr 3 Apr 6 Yes Yes
Apr 3 May 1 Yes Yes
Apr 3 May 6 Yes Yes
Another way to put the question: if the months are different, do we need to compare the day of month too?
I like your attitude. In accordance with your title I am not giving away the correctly working code. I too am convinced that you will not only learn more from writing it yourself, it will also give you greater pleasure. If you’re still stuck, please leave a comment and I’ll take one more look.
EDIT: For the problem of getting a negative result if the dates are in the opposite order: The simplest solution is to check the result after you’ve calculated. If it is negative, redo the entire calculation with the dates reversed. That is, with this. and comparedDate. in each other’s places. One elegent option is that in this case you tell the other MyDate object to do the calculation instead. Call the differenceInYears method of the other object passing this as argument.

Java: addToDay function

I'm trying to setup my addToDay function. I'm currently stuck on how to proceed with this or even write it correctly. The function itself will take a variable that ranges from -100 to 100. So you would basically add that variable to the current and if it was below the 0 then subtract a month or if it was above the months max day then add a month. Which i have that function setup so all i would have to do is call addToMonth with the correct amount. My problem lies within the amount of days each month has. For example, October has 31 days while November has 30. I have a function that will return the number of days in the current set month so i can call that to get how many max days should be in the current month. I'm thinking maybe a while loop would work but i just wanted to get anyone's thoughts on the best way to set it up.
I have 3 private ints: month, day, year. These are what need to be changed. I have both addTo functions for month and year setup already.
Here are some other functions i have created that can be used in this:
1. addToMonth(int delta) - changes the current month depending on the given parameter
2. getDaysInMonth() - will return the days in a month depending on the month itself
3. validateDay() - Will return true or false if the days fall outside the wanted requirements.
I don't want to use the calendar utility
I also don't want to use any other utilities. Just the base code with Junit for testing
Joda's plusDays() function and Java 8 LocalDate already has the logic that you are trying to achieve
Alright so i ended up just copying my original addToMonth function and modifying it abit to fit with days. So far it works but i do think it'll fail in the cases of different amounth of days not lining up.

Group and count duplicate values in arraylist java

I have used ArrayLists in my application, so I do not want to move to HashMaps as I have seen a few answers using this but did not work in my case.
I am creating my final high school project which is a study time table scheduler. I have managed to sort the ArrayList by date of the exam, but now I am trying to analyze the time table to rate it and compare the ratings with other generated timetables to give the user the best timetable (with the highest value).
I have gotten the timetable to output what they will be doing on each day ie: Afrikaans, IT, LO, Maths, Afrikaans, Afrikaans, etc.
But it seems that it duplicates on the last one for a long time even if the two last exams are within 2 days or very close together, the last one will be more dominant in the entire list. Like this:
Exam Dates:
LO = 2 Sep
Maths = 5 Sep
IT = 9 Sep
Afrikaans = 10 Sep
Results:
LO
IT
Afrikaans
Maths
IT
Afrikaans
Afrikaans
Afrikaans
Afrikaans
As you can see, the result is much more weighted towards the last given subject.
Now I am trying to compare and group the data so I can see how many days were allocated to each subject, so using the above example I need it to look like this:
LO = 1
Maths = 1
IT = 2
Afrikaans = 5
So far I have this:
ArrayList<Day> days = new ArrayList<Day>();
For(int i = 0; i < timeTable.size(); i++) {
// need to group the days here
if(days.contains(timeTable.get(i))) {
days.get(i).incrementNumberOfDays();
} else {
days.add(timeTable.get(i));
}
}
But that is not grouping the data and counting the duplicates.
Please help, my project is due in a week and I have spent two months on it. I am almost finished and am stuck here.
Thanks in advance!
You can use java.util.Collections.frequency:
int count = Collections.frequency(timeTable, value);
Edit: answer to your last question in comment:
Surely there is a quick simple way to say this value occurred 3 times
in the arraylist?
It's necessary to mention that in your timeTable, assuming it contains two same Day - Afrikaans - 1, when you see they are the same, the contains function doesn't think so. Although they have the same value for each property, but not the hashcode.
You need to override the function of equals() to make sure that when comparing two Day, if they have the same value, they are regarded as one object.
Sorry for my poor English, hope you can get it.

How to improve this algorithm which fills up a calendar grid?

I have Grid which will render a calendar, and I'm provided with an ArrayList<CalendarEventEntity> which contains events. Those events have to be highlighted in the grid.
As I have to fill the grid by my self I have something like this:
for( loop through the days of the month ){
Calendar eventDate = event.getDate();
// look for the events in the calendar that matchs this day
for(CalendarEventEntity event : events) {
// if there are events in this specific day
if( eventDate.get(Calendar.YEAR) == calendarMonth.get(Calendar.YEAR) &&
eventDate.get(Calendar.MONTH) == calendarMonth.get(Calendar.MONTH) &&
eventDate.get(Calendar.DAY_OF_MONTH) == dayIndex ) {
// highlight it!!!
}
}
}
This works fine, but it's too slow. So I want to speed it up! I added this before the inner for:
// ignore dates which does not make part of this month or year
if( eventDate.get(Calendar.YEAR) < calendarMonth.get(Calendar.YEAR) ||
eventDate.get(Calendar.MONTH) < calendarMonth.get(Calendar.MONTH) ||
eventDate.get(Calendar.DAY_OF_MONTH) != DateIdx ) {
continue;
}
// stop when processing dates which are higher than this month or year
if( eventDate.get(Calendar.YEAR) > calendarMonth.get(Calendar.YEAR) ||
eventDate.get(Calendar.MONTH) > calendarMonth.get(Calendar.MONTH)
|| eventDate.get(Calendar.DAY_OF_MONTH) != DateIdx ) {
break;
}
and that made if faster, but it's still too slow. How can I improve this algorithm?
The problem is that each day you have to search every event looking for events on that date. You need to find a way to only be searching through events on that day, or to know if events are on that day at all.
You should consider using a HashMap to store your events indexed by date. Then you can just check to see if there's a HashMap entry for the day in question. You'll have to pick a way to represent a day that would be universal enough to be used as a key.
This will also be handy when you have to drill down into the details of one specific day and show only the events on that day. You shouldn't have to search through all events every time you want to find events for one specific day.
This is a classic example of a problem that would benefit from using a (sorted) tree. Java provides one in TreeMap. You can get events that begin on a day using the subMap method. Calendar implements Comparable, so it should just work. (Use the calendar entries as keys; use subMap from the last second of the preceding day to the first second of the following day to get all events that are on the day in question.)
If you have many multi-day events, then you'd need an interval tree, but it might just be easier to split the single event "Five Day Workshop" into five entries "Workshop, Day One of Five" etc. so that no events spill over from one day to another.

Categories

Resources