Iterator between two given hours - java

I was in a job interview and got this question: " Write a function that gets 2 strings s,t that represents 2 hours ( in format HH: MM: SS ). It's known that s is earlier than t.
The function needs to calculate how many hours between the two given hours contains at most 2 digits.
For example- s- 10:59:00, t- 11:00:59 -
Answer- 11:00:00, 11:00:01,11:00:10, 11:00:11.
I tried to do while loops and got really stuck. Unfortunately, I didn't pass the interview.
How can I go over all the hours (every second is a new time) between 2 given hours in java as explained above? Thanks a lot

Java 8 allows you to use LocalTime.
LocalTime time1 = LocalTime.parse(t1);
LocalTime time2 = LocalTime.parse(t2);
The logic would require you to count the amount of different digits in a LocalTime, something like
boolean isWinner(LocalTime current) {
String onlyDigits = DateTimeFormatter.ofPattern("HHmmss").format(current);
Set<Character> set = new HashSet<>();
for (int index = 0; index < onlyDigits.length(); index++) {
set.add(onlyDigits.charAt(index));
}
return set.size() <= 2;
}
You can loop between the times like this
int count = 0;
for (LocalTime current = time1; current.isBefore(time2); current = current.plusSeconds(1)) {
if (isWinner(current)) {
count++;
}
}
That's it.
The question is really more geared towards getting a feel of how you'd approach the problem, and if you know about LocalTime API etc.

Related

Comparing an arrayList to itself using foreach and not including duplicates

I'm comparing an arrayList to itself using foreach.
I have an arrayList containing tips for waiters, each object has a date "dd-MM-yyy" and an amount (double),
Now i want to add all transactions for the same day, so i get a total for the day that can be divided between the waiters.
Without duplicates.
I've looked all over especially here, but I can't seem to find a solution.
I really hope you guys can help, I know it's a bit embarrassing, seeing as the problem being so simple, but I've been working on it for a couple of days now and I'm stuck.
I had a longer algorithm but it wouldn't work and I couldn't find any solutions online, so i broke it all down to it's most basic components and checked for each step and pretty early on this problem occured:
I'm using a local arrayList to make sure that I'm not comparing the same days to eachother over and over again.
The if(!alreadyMade.contains(tips1.getTime()) followed by alreadyMade.add(tips1.getTime()) seems to be producing duplicates, which in my mind makes no sense.
All I want is to add all the transactions for the same day from the same arrayList.
public void dist(){
double day = 0;
List<String> alreadyMade = new ArrayList<>();
for (Tips tips : data.getTips()) {
for (Tips tips1 : data.getTips()) {
if(tips.getTime().equals(tips1.getTime())) {
if (!alreadyMade.contains(tips1.getTime())){
alreadyMade.add(tips1.getTime());
day += tips.getTips();
}
}
}
System.out.println(day);
day = 0;
}
}
I wanted the print to be for a single day, but it is printing a lot of numbers that doesn't make sense
I think you're trying to do something like this:
Map<String,Double> alreadyMade = new HashMap<>();
for (Tips tips : new ArrayList<Tips>()) {
// If this time doesn't exist in the map then add it to the map with the
// value tips.getTips(). If this time does exist in the map then add
// the value of tips.getTips() to the value that is already in the map.
alreadyMade.merge(tips.getTime(), tips.getTips(), (Double a, Double b) -> a + b);
}
// go through each map entry. The keys are the times and the values are the tip totals for that time.
for (Map.Entry<String, Double> entry : alreadyMade.entrySet()) {
System.out.println("Time: " + entry.getKey() + " Tips: " + entry.getValue());
}
Note: I couldn't test this because I'm running Java 7 and this map function isn't available until java 8.
In Java 8+ you can use the stream API to group by the time:
Map<Date, Integer> alreadyMade = data.getTips().stream()
  .collect(groupingBy(Tip::getTime, summingInt(Tip::getTips)));
I would do it like the following:
This is your Tip class(I think)
public class Tip{
Date date;
float tip;
public Tip(Date date, float tip){
this.date = date;
this.tip = tip;
}
}
And this is the ("Algorithm")
//To Format the Dates
SimpleDateFormat ft = new SimpleDateFormat("dd-MM-yyyy");
//Input
ArrayList<Tip> tips = new ArrayList<Tip>();
//Just some Data for testing
tips.add(new Tip(ft.parse("11-04-2019"), 2.40F));
tips.add(new Tip(ft.parse("25-04-2019"), 3.30F));
tips.add(new Tip(ft.parse("25-04-2019"), 0.90F));
//Output
ArrayList<Date> dates = new ArrayList<Date>();
ArrayList<Float> sum = new ArrayList<Float>();
for(Tip tip : tips){ //Go through each Tip
int match = dates.indexOf(tip.date); //Look if the date is already in the array (if not -> -1)
if(match == -1){ //If not add it
dates.add(tip.date);
sum.add(tip.tip);
}else { //If yes set it
sum.set(match, sum.get(match) + tip.tip);
}
}
//Output to console
for(int i = 0; i < dates.size(); i++){
System.out.println(ft.format(dates.get(i)).toString() + " " + String.valueOf(sum.get(i)));
}
There is also a solution with maps or pairs but I never worked with them (not a professional coder). Also make sure to try-catch the ParseException. I Hope thats what you meant. :)

Java : given a list of object that has range of dates find two objects whose end month is closest to current date month

List of dates are as below (The list can be in any order):
3-Jan to 31-Mar, 2-Apr to 30-Jun, 1-Jul to 30-Sep, 4-Oct to 31-Dec
Current Date is: 19-Feb
Can someone please help me with the logic?
My approach is:
if(the given date should be greater than start date and less than end date){//this gives current quarter}else if(difference of the month of current date from the end date of each object should be less than or equal to 5)
i am hard coding the condition less than 5, which may break if in future the range of date will be of 4 months
Second approach is:
we can sort the list in ascending order and can get the current quarter index by comparing with current date and the next quarter will be of next index. But the complexity will be more.
I tried below code, but it gives only current quarter date. I am not able to get next quarter considering there would be only 3 objects and current date month is feb.
public static List getCurrentQtrOffr(List detail,Date currentDate) throws ParseException{
int currentQuarter = 9999, diff1;
int nextquarter = 9999, diff2;
Detail detail1;
Detail detail2;
Detail detail3 = null;
Detail detail4 = null;
Iterator<Detail> iterator = detail.iterator();
List<Detail> list = new ArrayList<Detail>();
while(iterator.hasNext()){
detail1 = iterator.next();
diff1 = getDiff(currentDate,detail1.startTime());
if(diff1>0){
if(iterator.hasNext()){
detail2 = iterator.next();
}else{
detail2 = null;
}
if(detail2 != null){
diff2 = getDiff(currentDate,detail2.startTime());
if(diff1 < diff2 ){
if(currentQuarter > diff1){
nextquarter = currentQuarter;
currentQuarter = diff1;
//how to assign detail3 before updating it with next minimum value, as if there will be only 3 object and flow comes in this if block then detail4 will be null
detail4=detail3;
detail3=detail1;
}else if(nextquarter > diff1){
nextquarter = diff1;
detail4=detail1;
}
}else{
if(currentQuarter > diff2){
nextquarter = currentQuarter;
currentQuarter = diff2;
detail4=detail3;
detail3=detail1;
}else if(nextquarter > diff2){
nextquarter = diff2;
detail4=detail1;
}
}
}else{
if(currentQuarter > diff1){
nextquarter = currentQuarter;
currentQuarter = diff1;
detail4=detail3;
detail3=detail1;
}else if(nextquarter > diff1){
nextquarter = diff1;
detail4=detail1;
}
}
}else{
System.out.println("skipped "+diff1);
}
}
list.add(detail3);
list.add(detail4);
return list;
}
If the periods are mutually exclusive (not overlapping) the you simply check for the first occurrence where:
The target is equal to or later than the start, and…
The target is before the stop.
This logic follows the Half-Open approach commonly used in date-time work where the beginning is inclusive while the ending is exclusive.
A shorter way of saying "the target is equal to or later than the start" is "not before start". The exclamation mark ! means not in Java syntax.
Boolean periodContainsTarget = ( ! target.isBefore( start ) ) && target.isBefore( stop ) ;
The above logic would be used with LocalDate if you meant date with a year. If you literally meant a month and day without a year, use the MonthDay class. The logic works for both.
Use Period class to represent the span of time between a pair of LocalDate objects. See Tutorial.
You might also find useful the Interval class in the ThreeTen-Extra project that supplements java.time.

Find the top N most popular elements

I have a List of TrackDay objects for a runner going around a track field on different days. Each pair of start/finish times signal a single lap run by the runner. We are guaranteed that there is a matching start/finish date (in the order in which they appear in the appropriate lists) :
TrackDay() {
List<DateTime> startTimes
List<DateTime> finishTimes
}
I would like to find the top N days (lets say 3) that runner ran the most. This translates to finding the N longest total start/finish times per TrackDay object. The naive way would be to do the following:
for (TrackDay td : listOftrackDays) {
// loop through each start/finish lists and find out the finish-start time for each pair.
// Add the delta times (finish-start) up for each pair of start/finish objects.
// Create a map to store the time for each TrackDay
// sort the map and get the first N entries
}
Is there a better, more clean/efficient way to do the above?
The problem you're trying to solve is well-known as Selection algorithm, in particular - Quick select. While sorting in general works good, for large collections it would be better to consider this approach, since it will give you linear time instead of N*log(N).
This solution should be linear time. I have assumed that startTimes and finishTimes support random access. I don't know what API your DateTime is part of, so have used java.time.LocalDateTime.
public List<TrackDay> findTop(List<TrackDay> trackDays, int limit) {
limit = Math.min(limit, trackDays.size());
List<Duration> durations = new ArrayList<>(Collections.nCopies(limit, Duration.ZERO));
List<TrackDay> result = new ArrayList<>(Collections.nCopies(limit, null));
int lastIndex = limit - 1;
for (TrackDay trackDay : trackDays) {
Duration duration = Duration.ZERO;
for (int i = 0, n = trackDay.startTimes.size(); i < n; i++) {
duration = duration.plus(Duration.between(trackDay.startTimes.get(i), trackDay.finishTimes.get(i)));
}
Integer destinationIndex = null;
for (int i = lastIndex; i >= 0; i--) {
if (durations.get(i).compareTo(duration) >= 0) {
break;
}
destinationIndex = i;
}
if (destinationIndex != null) {
durations.remove(lastIndex);
result.remove(lastIndex);
durations.add(destinationIndex, duration);
result.add(destinationIndex, trackDay);
}
}
return result;
}

How to generate series of ascending number that include date element?

Hello. I want to create a function that generates ascending numbers.
For example, if today's date is June 21st, 2013 then the numbers will be 130621001.
The last three digits are ascending numbers, and it'll reset back to 001 on each date.
I can figure out on how to make the date digits, but I'm stuck with those last three digits.
Thank you in advance.
try this, good luck
public static String NextNumber(String currentNumber) {
//assume yymmddnnn
String sDateNum = currentNumber.substring(0, 6);
String sCurrentNum = currentNumber.substring(6,9);
int i = Integer.valueOf("1" + sCurrentNum);
i++;
return sDateNum + String.valueOf(i).substring(1, 4);
}
System.out.println(NextNumber("130621001"));
The real question is how you know what your previous answer was.
today = myDateFormatter(System.currentTimeMillis());
if (today.equals(oldDay)) count++;
else count == 0;
oldDay = today;
If this is a long running process, oldDay and count can be simple fields in your class. If the process exits and restarts, you will need to get your old answers from somewhere and set them to the largest value.

Parsing a List<List<String>> in Android?

I'm developing a custom Adsense report tool using Google Java Client Library for Android. I've successfully authenticated and can make API calls to the server. but now when I receive the response, I don't know how to parse it and correctly show the result to user.
According to the javaDocs, AdsenseReportsGenerateResponse.getRows() generates a List> But I'm kinda lost how to properly parse it to get:
-Today's earnings
-Yesterday's earnings
-Last 7 days
-Last month
-From the beginning of time
Here's part of my code related to the question
Reports.Generate request = adsense.reports().generate(startDate, endDate);
request.setMetric(Arrays.asList("PAGE_VIEWS", "AD_REQUESTS", "AD_REQUESTS_COVERAGE", "CLICKS",
"AD_REQUESTS_CTR", "COST_PER_CLICK", "AD_REQUESTS_RPM", "EARNINGS"));
request.setDimension(Arrays.asList("DATE", "WEEK", "MONTH"));
request.setSort(Arrays.asList("+DATE"));
AdsenseReportsGenerateResponse response = request.execute();
//TODO: Here be dragons
response.getRows();
Edit: Here is the javaDoc which mentions the getRow()
Hmm it seems nobody on this site can help?!
You should find our sample code useful: http://code.google.com/p/google-api-java-client/wiki/APIs#AdSense_Management_API
Namely, this is the file you're interested in: http://code.google.com/p/google-api-java-client/source/browse/adsense-cmdline-sample/src/main/java/com/google/api/services/samples/adsense/cmdline/GenerateReport.java?repo=samples
Here's a snippet of code to print the output. Mind you, this is for a command line application, but should be easily adaptable:
if ((response.getRows() != null) && !response.getRows().isEmpty()) {
// Display headers.
for (AdsenseReportsGenerateResponseHeaders header : response.getHeaders()) {
System.out.printf("%25s", header.getName());
}
System.out.println();
// Display results.
for (List<String> row : response.getRows()) {
for (String column : row) {
System.out.printf("%25s", column);
}
System.out.println();
}
System.out.println();
} else {
System.out.println("No rows returned.");
}
As for getting the data for different periods of time, you should probably be running different reports, not cramming it all into one, as that would take different start dates and end dates. Here's how it works:
Today's earnings: set the start and end dates to today, set the dimension list to just DATE
Yesterday's earnings: set the start and end date to yesterday, set the dimension list to just DATE
Last 7 days: if you want data per day, then you set the start date to 7 days ago, the end date to today, and the dimension list to just DATE. If you want to aggregate the stats, you may need to calculate this yourself, as WEEK and MONTH refer to a calendar week and month, not the last 7 days.
Last month: start date 1st of last month, end date last day of the month, dimension MONTH.
All time: how do you want this aggregated? Per month? Then set the start date to, say, 1980-1-1, end date to today and dimension to MONTH.
This blog post should help with understanding reporting concepts a bit better: http://adsenseapi.blogspot.com/2011/11/adsense-management-api-diving-into.html
Let me know if you need help with anything else!
Its not a List<List> as far as I understand the api. Try this:
String[][] array = response.getRows();
for (int i = 0; i < array.getSize(); i++){
String dimension = array[i][0];
String metric = array[i][1];
//Do what you want with them
}
I am writing this because the API says it has a list of dimensions with one value for the string and one for the metric, as far as I understand.
If you expect several cells on each row (Which I believe the API doesn't work that way), you need to add another for inside and get the size of the current list probably with something like array[i].getSize()
Post back if it doesn't help you.
Edit: I see now. Try this:
List list = response.getRows();
for (int i = 0; i < list.size(); i++){
List<String> list2 = list.get(i);
for (int j = 0; j < list2.size(); j++){
String value = list2.get(j);
//Do what you want
}
}

Categories

Resources