Skip to content

Instantly share code, notes, and snippets.

@deyindra
Created February 21, 2017 00:45
Show Gist options
  • Save deyindra/f54171e01bbfe694930f24843daba4cd to your computer and use it in GitHub Desktop.
Save deyindra/f54171e01bbfe694930f24843daba4cd to your computer and use it in GitHub Desktop.
AssertJ
package org.idey.algo.util;
import java.util.function.Predicate;
/**
* Assertion Utility class which will Assert statement in case statement is false,
* it will throw IllegalArgument Exception.
*/
public class AssertJ {
private AssertJ(){
throw new AssertionError("Invalid Access");
}
/**
*
* @param object which will satisfy following code
* <pre>
* new Predicate&lt;T&gt;(){
* public boolean test(T t){
* return t!=null;
* }
* }
* </pre>
* @param message Error message in case Predicate fails
* @param <T> describe the type of the object
* @throws IllegalArgumentException in case passed object is null
*/
public static <T> void notNull(T object, String message){
assertTrue(t -> t!=null,object,message);
}
/**
*
* @param predicate {@link Predicate} to test the condition
* @param object Object which will satisfy the predicate
* @param message Error message
* @param args Argument to format the message
* @param <T> describe the type of the object
* @throws IllegalArgumentException throws {@link IllegalArgumentException} in case Asserttion fails
*/
public static <T> void assertTrue(Predicate<? super T> predicate, T object, String message, Object... args){
if(!predicate.test(object)){
message = getFinalErrorMessage(message, args);
if(message==null){
throw new IllegalArgumentException();
}else{
throw new IllegalArgumentException(message);
}
}
}
/**
*
* @param message Error Message in can be null or empty
* @param args Arguments for format the error message
* @return Empty Error Message in case this is null or empty or actual error message
*/
private static String getFinalErrorMessage(String message, Object... args){
String actualMessage=null;
if(message!=null && !("").equals(message.trim())){
message = message.trim();
if(args!=null && args.length>0) {
actualMessage = String.format(message, args);
}else{
actualMessage = message;
}
}
return actualMessage;
}
}
package org.idey.algo.iterator.peek;
import java.util.Iterator;
/**
* Special Iterator which will provide addiotnal method {@link PeekIterator#peek()}
* @param <T> return the current object
*
*/
public interface PeekIterator<T> extends Iterator<T> {
/**
* This method always current element from the iterator. During the process of peeking element it will not
* advance the iterator
* @return T current object
* @throws java.util.NoSuchElementException in case there is no more elements or the iterator is null
*/
T peek();
/**
* @throws UnsupportedOperationException as this is not supported
*/
default void remove() {
throw new UnsupportedOperationException("Invalid Operations");
}
}
package org.idey.algo.iterator.peek;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Special Iterator which will provide addiotnal method {@link SimplePeekIterator#peek()}
* @param <T> element of the iterator
* @see PeekIterator
*/
public class SimplePeekIterator<T> implements PeekIterator<T> {
private Iterator<T> iterator;
private T element;
/**
* @param iterator underlying iterator
*/
public SimplePeekIterator(Iterator<T> iterator) {
this.iterator = iterator;
if (iterator!=null && iterator.hasNext()) {
element = iterator.next();
}
}
/**
* this method will not advance to next element
* @return T current element
* @throws NoSuchElementException in case hasNext return false
*/
@Override
public T peek() {
if(!hasNext()){
throw new NoSuchElementException("No more element");
}
return element;
}
/**
*
* @return false whem element is null
*/
@Override
public boolean hasNext() {
return element != null;
}
/**
* @return T next element
* @throws NoSuchElementException in case hasNext return false
*/
@Override
public T next() {
if(!hasNext()){
throw new NoSuchElementException("No more element");
}
T ret = element;
element = this.iterator.hasNext() ? iterator.next() : null;
return ret;
}
}
package org.idey.algo.iterator.timeseries;
import org.idey.algo.iterator.peek.PeekIterator;
import org.idey.algo.iterator.peek.SimplePeekIterator;
import org.idey.algo.util.AssertJ;
import java.time.Instant;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* {@link TimeSeries} based Sliding window {@link Iterator} which will return all elements based on
* {@link SlidingTimeSeriesIterator#size} and then slide by {@link SlidingTimeSeriesIterator#step}
*/
public class SlidingTimeSeriesIterator<T extends Comparable<T>> implements Iterator<Map<Long, SortedSet<TimeSeries<T>>>> {
private final TimeWindow timeWindow;
private final PeekIterator<TimeSeries<T>> iterator;
private final int size;
//Steps from from where window start
private final int step;
private final Deque<Long> deque;
private final Map<Long, SortedSet<TimeSeries<T>>> map;
private final Instant startDuration;
private boolean hasNext;
/**
*
* @param timeWindow unit size of time window it will be either {@link TimeWindow#SECONDS},
* {@link TimeWindow#MINUTES}, {@link TimeWindow#HOURS}, {@link TimeWindow#DAYS}
* @param iterator {@link TimeSeries} {@link Iterator}
* @param size size of the time window
* @param step Step by which window will slide
*/
public SlidingTimeSeriesIterator(TimeWindow timeWindow,
Iterator<TimeSeries<T>> iterator,
int size, int step) {
AssertJ.notNull(timeWindow, "Invalid time window");
AssertJ.notNull(iterator, "ietartor can not be null");
AssertJ.assertTrue(i->i>0, size, "size can not be zero or negative");
AssertJ.assertTrue(i->i>0, step, "step can not be zero or negative");
this.timeWindow = timeWindow;
this.iterator = new SimplePeekIterator<>(iterator);
this.size = size;
this.step = step;
map = new HashMap<>();
deque = new LinkedList<>();
hasNext=false;
startDuration = this.iterator.peek().getTs();
setAdvance();
}
@Override
public boolean hasNext() {
return hasNext;
}
@Override
public Map<Long, SortedSet<TimeSeries<T>>> next() {
if(!hasNext()){
throw new NoSuchElementException("No more elements");
}
Map<Long,SortedSet<TimeSeries<T>>> returnMap = Collections.unmodifiableMap(new HashMap<>(map));
setAdvance();
return returnMap;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Invalid operations....");
}
private void setAdvance() {
hasNext = false;
long nextValue=0;
if (iterator.hasNext()) {
if (!deque.isEmpty()) {
if(size>step){
for(int count=0;!deque.isEmpty() && count<step; count++){
long value = deque.poll();
map.remove(value);
}
nextValue = deque.peekLast();
}else if(size<=step){
nextValue = deque.peekLast();
long endStepValue = nextValue + step - size;
deque.clear();
map.clear();
while(iterator.hasNext()){
nextValue = calculateTimeDifference();
if(nextValue>endStepValue){
nextValue = endStepValue;
break;
}
iterator.next();
}
}
}
//Fill the gap here
while (iterator.hasNext() && deque.size()<size){
long timeDifference = calculateTimeDifference();
if(nextValue+1<timeDifference){
nextValue++;
while (nextValue<timeDifference && deque.size()<size){
deque.add(nextValue);
populateMap(nextValue);
nextValue++;
}
}
if(deque.size()<size){
if(!map.containsKey(timeDifference)){
deque.add(timeDifference);
}
populateMap(timeDifference,Optional.of(iterator.next()));
nextValue = timeDifference;
}
}
if(!deque.isEmpty()) {
hasNext = true;
}
}
}
private long calculateTimeDifference(){
TimeSeries<T> currentTsData = iterator.peek();
return timeWindow.calculate(startDuration,currentTsData.getTs());
}
private void populateMap(long count){
populateMap(count,Optional.empty());
}
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private void populateMap(long count, Optional<TimeSeries<T>> timeSeries){
SortedSet<TimeSeries<T>> sortedSet = map.computeIfAbsent(count, k -> new TreeSet<>());
timeSeries.ifPresent(sortedSet::add);
}
}
package org.idey.algo.iterator.timeseries;
import org.idey.algo.util.AssertJ;
import java.time.Instant;
/**
* TimeSeries data which will contain {@link Comparable} object and {@link Instant}
* @param <T> object which implements {@link Comparable}
*/
public class TimeSeries<T extends Comparable<T>> implements Comparable<TimeSeries<T>> {
private T object;
private Instant ts;
/**
* @param object {@link Comparable} and with {@link Instant#now()}
*/
public TimeSeries(T object) {
this(object, Instant.now());
}
public TimeSeries(T object, Instant d){
AssertJ.notNull(object, "Object can not be null");
AssertJ.notNull(d, "Date can not be null");
this.object = object;
this.ts = d;
}
public T getObject() {
return object;
}
public Instant getTs() {
return ts;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TimeSeries<?> that = (TimeSeries<?>) o;
return (object != null ? object.equals(that.object) : that.object == null)
&& (ts != null ? ts.equals(that.ts) : that.ts == null);
}
@Override
public int hashCode() {
int result = object != null ? object.hashCode() : 0;
result = 31 * result + (ts != null ? ts.hashCode() : 0);
return result;
}
@SuppressWarnings("ConstantConditions")
@Override
public int compareTo(TimeSeries<T> o) {
if(o==null){
return 1;
}else if(this==o){
return 0;
}else{
Instant thisDate = this.ts;
Instant otherDate = o.ts;
if(thisDate==null){
return -1;
}else{
int retValue = thisDate.compareTo(otherDate);
if(retValue==0){
T obj = this.object;
T anotherObject = o.object;
if(obj==null){
return -1;
}else{
return obj.compareTo(anotherObject);
}
}
return retValue;
}
}
}
@Override
public String toString() {
return "TimeSeries{" +
"object=" + object +
", ts=" + ts +
'}';
}
}
package org.idey.algo.iterator.timeseries;
import org.idey.algo.util.AssertJ;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
/**
* TimeWindow which will define difference between two {@link Instant}
* @see TimeWindow#SECONDS
* @see TimeWindow#MINUTES
* @see TimeWindow#HOURS
* @see TimeWindow#DAYS
*/
public enum TimeWindow {
//Return time difference in seconds
SECONDS{
@Override
public long calculate(Instant t1, Instant t2) {
checkValidity(t1, t2);
return ChronoUnit.SECONDS.between(t1, t2);
}
},
//Return time difference in minutes
MINUTES{
@Override
public long calculate(Instant t1, Instant t2) {
checkValidity(t1, t2);
return ChronoUnit.MINUTES.between(t1, t2);
}
},
//Return time difference in hours
HOURS{
@Override
public long calculate(Instant t1, Instant t2) {
checkValidity(t1, t2);
return ChronoUnit.HOURS.between(t1, t2);
}
},
//Return time difference in days
DAYS{
@Override
public long calculate(Instant t1, Instant t2) {
checkValidity(t1, t2);
return ChronoUnit.DAYS.between(t1, t2);
}
};
private static void checkValidity(Instant t1, Instant t2){
AssertJ.notNull(t1, "Duration can not be null");
AssertJ.notNull(t2, "Duration can not be null");
}
public abstract long calculate(final Instant t1, final Instant t2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment