Created
November 10, 2014 20:49
-
-
Save ChristianWilkie/48cda58d2ed08d69d451 to your computer and use it in GitHub Desktop.
[11/05/2014] Challenge #187 [Intermediate] Finding Time to Reddit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.christianwilkie; | |
import java.time.LocalDateTime; | |
import java.time.format.DateTimeFormatter; | |
/** | |
* Created by chris on 11/9/2014. | |
*/ | |
public class PostItNote implements Comparable<PostItNote>{ | |
private static final DateTimeFormatter printedDateFormatter = DateTimeFormatter.ofPattern("MM-dd-yyyy"); | |
private static final DateTimeFormatter printedTimeFormatter = DateTimeFormatter.ofPattern("hh:mm a"); | |
private LocalDateTime startTime; | |
private LocalDateTime endTime; | |
private String data; | |
public PostItNote(LocalDateTime startTime, LocalDateTime endTime, String data) { | |
this.startTime = startTime; | |
this.endTime = endTime; | |
this.data = data; | |
} | |
@Override | |
public int compareTo(PostItNote o) { | |
return this.startTime.compareTo(o.startTime); | |
} | |
@Override | |
public String toString() { | |
return printedTimeFormatter.format(startTime.toLocalTime()) + " to " + printedTimeFormatter.format(endTime.toLocalTime()) + | |
" -- " + data; | |
} | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
PostItNote that = (PostItNote) o; | |
if (data != null ? !data.equals(that.data) : that.data != null) return false; | |
if (endTime != null ? !endTime.equals(that.endTime) : that.endTime != null) return false; | |
if (startTime != null ? !startTime.equals(that.startTime) : that.startTime != null) return false; | |
return true; | |
} | |
@Override | |
public int hashCode() { | |
int result = startTime != null ? startTime.hashCode() : 0; | |
result = 31 * result + (endTime != null ? endTime.hashCode() : 0); | |
result = 31 * result + (data != null ? data.hashCode() : 0); | |
return result; | |
} | |
public LocalDateTime getStartTime() { | |
return startTime; | |
} | |
public void setStartTime(LocalDateTime startTime) { | |
this.startTime = startTime; | |
} | |
public LocalDateTime getEndTime() { | |
return endTime; | |
} | |
public void setEndTime(LocalDateTime endTime) { | |
this.endTime = endTime; | |
} | |
public String getData() { | |
return data; | |
} | |
public void setData(String data) { | |
this.data = data; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.christianwilkie; | |
import com.google.common.collect.Iterators; | |
import com.google.common.collect.PeekingIterator; | |
import java.io.BufferedReader; | |
import java.io.FileReader; | |
import java.io.IOException; | |
import java.text.DecimalFormat; | |
import java.text.NumberFormat; | |
import java.time.Duration; | |
import java.time.LocalDate; | |
import java.time.LocalDateTime; | |
import java.time.LocalTime; | |
import java.time.format.DateTimeFormatter; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.TreeMap; | |
/** | |
* Created by chris on 11/9/2014. | |
*/ | |
public class PostItNoteParser { | |
private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("M[M]-d[d]-yyyy"); | |
private static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mma"); | |
//inner map: <start time, note> | |
private static TreeMap<LocalDate, TreeMap<LocalTime,PostItNote>> noteMap = new TreeMap<>(); | |
private static TreeMap<String,Duration> timeSpentMap = new TreeMap<>(); | |
private static Duration totalTimeSpentOnTasks = Duration.ZERO; | |
public PostItNoteParser() { | |
} | |
public static PostItNote parseLine(String line) { | |
String[] splitLine = line.split(" ");//split on the spaces | |
//super hacky and dangerous line parsing ahoy | |
//get rid of the ':' by splitting it out, then parse the result | |
//e.g. "11-6-2014:" -> "11-6-2014" | |
int preDataLength = 0; | |
LocalDate date = parseDate(splitLine[0].split(":")[0]); | |
//05:18, AM | |
LocalTime startTime = parseTime(splitLine[1]+splitLine[2]); | |
//skip the to, (3) | |
//06:00, AM | |
LocalTime endTime = parseTime(splitLine[4]+splitLine[5]); | |
//skip 6, | |
//the rest is data | |
for(int i = 0; i < 7; i++) { | |
//skip over all this pre-data stuff | |
preDataLength += splitLine[i].length()+1; | |
} | |
//now get the data substring | |
String data = line.substring(preDataLength); | |
return new PostItNote(LocalDateTime.of(date, startTime),LocalDateTime.of(date, endTime),data); | |
} | |
private static LocalDate parseDate(String date) { | |
//input: MM-DD-YYYY string | |
return LocalDate.parse(date,dateFormatter); | |
} | |
private static LocalTime parseTime(String time) { | |
return LocalTime.parse(time,timeFormatter); | |
} | |
private static PostItNote findBestRedditSlot(TreeMap<LocalTime,PostItNote> innerNoteMap) { | |
final String data = "reddit"; | |
Set<Map.Entry<LocalTime,PostItNote>> entrySet = innerNoteMap.entrySet(); | |
PeekingIterator<Map.Entry<LocalTime,PostItNote>> iterator = Iterators.peekingIterator(entrySet.iterator()); | |
Duration longestDurationForBrowsingReddit = Duration.ZERO; //keep track of longest possible duration | |
LocalDateTime startTimeForBrowsingReddit = null; | |
LocalDateTime endTimeForBrowsingReddit = null; | |
while(iterator.hasNext()) { | |
PostItNote firstItem = iterator.next().getValue(); | |
//if we aren't at the end of the day | |
if(iterator.hasNext()) { | |
PostItNote secondItem = iterator.peek().getValue(); | |
Duration timeBetweenTasks = Duration.between(firstItem.getEndTime(), secondItem.getStartTime()); | |
//if the duration between these 2 tasks is greater than any previously found duration between 2 tasks | |
if(timeBetweenTasks.compareTo(longestDurationForBrowsingReddit) > 0) { | |
longestDurationForBrowsingReddit = timeBetweenTasks; | |
startTimeForBrowsingReddit = firstItem.getEndTime(); | |
endTimeForBrowsingReddit = secondItem.getStartTime(); | |
} | |
} | |
} | |
return new PostItNote(startTimeForBrowsingReddit,endTimeForBrowsingReddit,data); | |
} | |
public static void main(String[] args) { | |
try(BufferedReader br = new BufferedReader(new FileReader("src/main/resources/challenge_input.txt"))) { | |
while(br.ready()) { | |
PostItNote note = parseLine(br.readLine()); | |
TreeMap<LocalTime,PostItNote> innerNoteMap = noteMap.get(note.getStartTime().toLocalDate()); | |
Duration taskDuration = Duration.between(note.getStartTime(),note.getEndTime()); | |
Duration previousTimeSpentInBucket; | |
if (innerNoteMap == null) { | |
//we need to make the inner maps first | |
innerNoteMap = new TreeMap<>(); | |
//make the inner note map | |
noteMap.put(note.getStartTime().toLocalDate(),innerNoteMap); | |
} | |
//insert the note | |
innerNoteMap.put(note.getStartTime().toLocalTime(), note); | |
//check the task duration map | |
previousTimeSpentInBucket = timeSpentMap.get(note.getData()); | |
if (previousTimeSpentInBucket == null) { | |
//if we haven't yet added this task to the time spent map, then treat the previous duration as 0 | |
previousTimeSpentInBucket = Duration.ZERO; | |
} | |
//insert the additional time spent | |
Duration summedDuration = taskDuration.plus(previousTimeSpentInBucket); | |
timeSpentMap.put(note.getData(), summedDuration); | |
//keep track of the total time spent on tasks | |
totalTimeSpentOnTasks = totalTimeSpentOnTasks.plus(taskDuration); | |
} | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
//now we have the data sorted and separated into date buckets | |
//we need to find the best times for browsing reddit | |
noteMap.entrySet().forEach((noteMapEntry)-> { | |
TreeMap<LocalTime,PostItNote> innerMap = noteMapEntry.getValue(); | |
PostItNote redditNote = findBestRedditSlot(innerMap); | |
//insert this note | |
innerMap.put(redditNote.getStartTime().toLocalTime(),redditNote); | |
//add to our statistic map | |
Duration previousTimeSpentOnReddit = timeSpentMap.get(redditNote.getData()); | |
if(previousTimeSpentOnReddit == null) { | |
previousTimeSpentOnReddit = Duration.ZERO; | |
} | |
Duration redditNoteDuration = Duration.between(redditNote.getStartTime().toLocalTime(), redditNote.getEndTime().toLocalTime()); | |
timeSpentMap.put(redditNote.getData(),previousTimeSpentOnReddit.plus(redditNoteDuration)); | |
//add the time spent to our running total | |
totalTimeSpentOnTasks = totalTimeSpentOnTasks.plus(redditNoteDuration); | |
}); | |
//now we found and inserted the best times for browsing reddit | |
//print out the notes | |
final DateTimeFormatter scheduleHeadingFormatter = DateTimeFormatter.ofPattern("EEEE, MMMM dd yyyy"); | |
noteMap.entrySet().forEach((noteMapEntry)-> { | |
System.out.println("Schedule for " + noteMapEntry.getKey().format(scheduleHeadingFormatter)); | |
TreeMap<LocalTime,PostItNote> innerMap = noteMapEntry.getValue(); | |
innerMap.entrySet().forEach((innerEntry) -> System.out.println(innerEntry.getValue())); | |
System.out.println(); | |
}); | |
//print out the statistics | |
NumberFormat percentageFormat = NumberFormat.getPercentInstance(); | |
percentageFormat.setMaximumFractionDigits(1); | |
System.out.println("Time spent on tasks:"); | |
timeSpentMap.entrySet().forEach((timeSpentMapEntry) -> { | |
Duration totalTaskDuration = timeSpentMapEntry.getValue(); | |
System.out.println(timeSpentMapEntry.getKey() + ": " + totalTaskDuration.toMinutes() + " minutes (" + | |
percentageFormat.format((double)totalTaskDuration.toNanos() / totalTimeSpentOnTasks.toNanos()) + " of total time)."); | |
}); | |
System.out.println(); | |
System.out.println("Total time spent on all tasks: " + totalTimeSpentOnTasks.toMinutes() + " minutes."); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment