JavaFX 8 Stacked Bar Chart numerical sorting issue - java

I'm developing an application that parses a text file and looks for times between certain sent actions, a simple visual aid in short.
My issue is that the sorting on the StackedBarCharts x-axis has gone awry, as shown by the image linked below;
Image of sorting issue
The relevant code for generating these charts;
public boolean updateBarChart(Tab t, DataHolder dock) {
Node n = t.getContent();
Node graph = n.lookup("#Graph");
StackedBarChart bc = (StackedBarChart) graph;
//Barchart
NumberAxis xAxis = new NumberAxis();
NumberAxis yAxis = new NumberAxis();
bc.setTitle("Summary");
bc.getData().clear();
bc.setLegendVisible(true);
bc.setCategoryGap(1);
xAxis.setTickLabelRotation(90);
ArrayList<String> tempArr = dock.getUniqueActionNumbers();
for(String s : tempArr)
{
bc.getData().add(dock.calculateIntervalsBetweenActions(s));
}
bc.getXAxis().setAutoRanging(true);
bc.getYAxis().setAutoRanging(true);
return true;
}
The code generating the series, where:
ConstantStrings are an ENUM of the constantly reocurring strings,
PairValue is a simple home brewed Pair made for a simple local caching system so I don't have search the entire data structure every time I want each instance of a specific value.
public XYChart.Series<String, Number> calculateIntervalsBetweenActions(String actionNumber)
{
XYChart.Series returnValue = new XYChart.Series();
returnValue.setName(actionNumber);
LocalTime lastTime = null;
TreeMap<Integer, Integer> listOfNumbers = new TreeMap<Integer, Integer>();
int maxVal = 0;
ArrayList<PairValue> temp = metaMap.get(ConstantStrings.RECIEVED_ACTION_NUMBER);
if (temp != null)
{
for( PairValue p : temp)
{
String s = dp.get(p.getNodePlace()).getTokens().get(p.getPointPlace()).getValue();
if (!s.equals(actionNumber))
continue;
if(lastTime != null)
{
LocalTime tempTime = LocalTime.parse(dp.get(p.getNodePlace()).getTimestamp());
int seconds = (int) lastTime.until(tempTime, SECONDS);
if(seconds > maxVal) maxVal = seconds;
Integer count = listOfNumbers.get(seconds);
listOfNumbers.put(seconds, (count == null) ? 1 : count + 1);
lastTime = tempTime;
}
else lastTime = LocalTime.parse(dp.get(p.getNodePlace()).getTimestamp());
}
//todo add filter so the user can choose what to ignore and not.
for(int i = 2; i <= maxVal; i++) {
Integer find = listOfNumbers.get(i);
if(find != null) {
XYChart.Data toAdd = new XYChart.Data(Integer.valueOf(i).toString(), find);
returnValue.getData().add(toAdd);
}
}
}
else Logger.getGlobal().warning("Could not find meta map for Recieved action numer, aborting");
return returnValue;
}
My suspicions lie in the order the Series are added, but that should not matter in my opinion, so my question stands; Is there any simple way to sort these values properly?

Found the solution after an extensive amount of banging my head against the wall of not understanding:
First of all, don't programatically skip adding any values to the original series. Add all 0-values ranging between the values you want to keep. This is for sorting purposes.
Remove all 0-values when you've finalized the adding of new data.
This is the snippet of code I've used to remove the 0-values, modify for your own purposes as you wish.
ObservableList<XYChart.Series> xys = bc.getData();
for(XYChart.Series<String,Number> series : xys) {
ArrayList<XYChart.Data> removelist = new ArrayList<>();
for(XYChart.Data<String,Number> data: series.getData()) {
if(data.getYValue().equals(0)) removelist.add(data);
}
series.getData().removeAll(removelist);
}

Related

Separate Array based on Gaps in linear key

I am looking to separate a single array into separate arrays based on gaps in the key. For example take this scenario:
I'm attempting to create separate datasets (arrays) for consecutive days of the month. If a day is missed a new dataset needs to be created starting with the next day that has a value.
The data is retrieved in one array like so:
[1:10, 2:8, 4:5, 5:12, 8:6, 9:10, 10:5, 11:4, 13:6, 14:5]
I would like to output:
[1:10, 2:8], [4:5, 5:12], [8:6, 9:10, 10:5, 11:4], [13:6, 14:5]
How would I achieve this?
I currently have this:
ArrayList<Entry> allValues = new ArrayList<>();
// Data Retrieval from the Server is Here (hidden for privacy)
// Each data entry contains key and value
// This is converted into a data model "Entry" which is essentially an x & y coordinate ( Entry(x,y) )
// and then added to the allValues List
List<ArrayList<Entry>> rawDataSets = new ArrayList<>();
ArrayList<Entry> tempDataSet = new ArrayList<>();
for(int i = 0; i < allValues.size(); i++){
Entry tempEntry = allValues.get(i);
if(i == tempEntry.getX()){
tempDataSet.add(tempEntry);
}else{
if(tempDataSet.size() > 0) {
rawDataSets.add(tempDataSet);
tempDataSet.clear();
}
}
}
Something like this should do trick:
ArrayList<Entry> allValues = new ArrayList<>();
// Assuming at this point that `allValues` is sorted in ascending order by X values.
// If necessary, it can be sorted with
//
// Collections.sort(allValues, Comparator.comparing(Entry::getX));
//
List<ArrayList<Entry>> rawDataSets = new ArrayList<>();
ArrayList<Entry> tempDataSet = new ArrayList<>();
for (Entry tempEntry : allValues){
if (!tempDataSet.isEmpty() &&
tempEntry.getX() != tempDataSet.get(tempDataSet.size()-1).getX() + 1)
{
// tempDataSet is not empty, and tempEntry's X is not
// consecutive with the X of tempDataSet's last entry, so it's
// it's time finish with the current tempDataSet and start fresh
// with a new one.
rawDataSets.add(tempDataSet);
tempDataSet = new ArrayList<>();
}
// Regardless of what happened, or didn't happen, with tempDataSet above,
// the current allValues entry now belongs with the current tempDataSet
tempDataSet.add(tempEntry);
}
// Now add any final non-empty tempDataSet (there will always be one if
// allValues wasn't empty) onto rawDataSets
if (!tempDataSet.isEmpty()) {
rawDataSets.add(tempDataSet);
}
After a number of attempts I think I found the solution, although I'm not sure if this is the most effective:
List<ArrayList<Entry>> rawDataSets = new ArrayList<>();
ArrayList<Entry> tempDataSet = new ArrayList<>();
for(int i = 0; i <= allValues.get(allValues.size() - 1).getX(); i++){
int matchedIndex = -1;
for(int j = 0; j < allValues.size(); j++){
if(allValues.get(j).getX() == i){
matchedIndex = j;
}
}
if(matchedIndex != -1) {
Entry tempEntry = allValues.get(matchedIndex);
tempDataSet.add(tempEntry);
} else {
if (tempDataSet.size() > 0) {
rawDataSets.add(tempDataSet);
tempDataSet = new ArrayList<>();
}
}
}

What is the correct way of using the map while getting the last update record from the list of object

What is the difference between the below two approach of getting the last updated record from the list and which one is better and why?
Example -
Assume List of Message contains the record in sequence where Message object would be:
Message
{
Integer id ;
String name ;
}
and value in the list called "messages" contains
[1 , "a"],[2, "b"],[1 , "b"],[1, "c"]
result should contain only these two record -
[2, "b"] ,[1, "c"]
Solution1 -
Map<Integer,String> latestMessage = new HashMap<>();
for (Message m : messages) {
latestMessage.put(m.getId(), m.getName());
}
Solution 2 -
Map<Integer,String> latestMessage = new HashMap<>();
for (Message m : messages) {
if(!latestMessage.containsKey(m.getId())) {
latestMessage.put(m.getId(), m.getName());
}
else {
latestMessage.replace(m.getId(), m.getName()) ;
}
}
I would go for the former (put) since you are not using the message or even trying to merge (I put emphasis on that because of Java 8 and merge method):
You don't do stuff like that either:
Map<String, List<String>> map = ...;
for (Message m : messages)
map.computeIfAbsent(m.getId(), k -> new ArrayList<>()).add(m.getName());
And if you were, you should probably use Stream and groupingBy as in:
messages.stream()
.collect(groupingBy(Message::getId, Message::getName));
Going back to your two use cases:
Using put is also shorter and is easier to understand: the latter (containsKey + put/replace) will be harder to understand (not that harder, but still, you'll have to read the code to understand it).
In terms of performance, using put should be a bit faster than checking if mapping exist because you do a little bit more operation. I would not put my hand on fire for that, but you will have to write a benchmark (using JMH) to compare which is better.
TL;DR: use put unless you can prove that containsKey + put/replace is better.
I tried the following code to see the performance difference between the approaches you've given:
public class MapPerformanceTest {
public static void main(String[] args) {
Map<Integer, Integer> map = new HashMap();
// fill the map with 50000 entities
int count = 50000;
for (int i = 0; i < count; i++) {
// value doesn't matter
map.put(i, getRandom(0, count));
}
// fill a set with one million entities
Set<Integer> set = new HashSet();
int setSize = 1000000;
for (int i = 0; i < setSize; i++) {
set.add(getRandom(0, count));
}
// use the set to test performance
long startTime = System.nanoTime(), endTime = 0;
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
int next = iterator.next();
map.put(next, getRandom(0, count));
}
endTime = System.nanoTime();
System.out.println(String.format("PUT: %d", endTime - startTime));
startTime = System.nanoTime();
iterator = set.iterator();
while (iterator.hasNext()) {
int next = iterator.next();
if(!map.containsKey(next)) {
map.put(next, getRandom(0, count));
}
else {
map.replace(next, getRandom(0, count)) ;
}
}
endTime = System.nanoTime();
System.out.println(String.format("REPLACE: %d", endTime - startTime));
}
private static int getRandom(int min, int max) {
return ThreadLocalRandom.current().nextInt(min, max + 1);
}
}
When running the above code, it prints on console the following:
PUT: 17171025
REPLACE: 18274190
Which means the first approach has slightly a better performance.

How to sort a linked list with objects and private variables

I am going to be honest and up front here. This is homework, but I have become desperate and am looking for anyone to assist me. I have been working on this off and on for over a month and have gone to my instructor multiple times. Basically this program needs to create and sort a linked list that has an int, string and double in each node. It needs to be able to sort by each data type as well as print in input order but once I figure one out I can transfer it to the other data types. Please, everything needs to be "hand made", please do not use any built in commands as I need to create everything as per my instructor's demands.
I attempted to make the linked list and then sort it, but I ran into a problem so I decided to try and sort the list as I create it.
For example: Input the first node, then input the next node in front/behind the first, then put the next where it needs to go... and so forth.
Here is my code (I only focus on the strings):
String repeat = "y";
list1 fChr = null;
list1 p = fChr;
list1 copy = null;
//list1 dCopy = null;
//list1 iCopy = null;
list1 fd = fChr;//front of the double list
list1 fi = fChr;//front of the integer list
list1 fStr = fChr;//front of the string list~
list1 pStr = fStr;
boolean inserted = false;
int iii = 0;
String sss = "";
double ddd = 0.0;
while(repeat.equals("y"))//while the user agrees to adding a new node
{
if(fChr == null)// if the front is empty
{
fChr = new list1();//create a new node by calling object and sets it as the front
p = fChr;
copy = fChr;
sss = fChr.GetS();
iii = fChr.GetI();
ddd = fChr.GetD();
copy.SetS(sss);
copy.SetI(iii);
copy.SetD(ddd);
System.out.println("(1)");
}
else
{
System.out.println("(2)");
if(p!=null)
{
System.out.println("p = "+ p.GetS());
if(p.next != null)
{
System.out.println("p.next = "+ p.next.GetS());
System.out.println("p.next.next = "+ p.next.next.GetS());
}
}
p = fChr;
while(p.next != null)//finds the end of the Linked list
{
System.out.println("(3)");
p = p.next;//moves the pointer p down the list
}
list1 NextNode = new list1();//
p.next = NextNode;
sss = NextNode.GetS();
iii = NextNode.GetI();
ddd = NextNode.GetD();
copy = NextNode;
String gg = "hi";//tests to see if the setter is actually changing the value inside copy(it is not, it prints b)
copy.SetS(gg);
copy.SetI(iii);
copy.SetD(ddd);
System.out.println(copy.GetS());
System.out.println("p = "+ p.GetS());
}
pStr = fStr;
//System.out.println(copy.GetS()+"*");
inserted = false;
if(fStr == null)
{
System.out.println("(4)");
fStr = copy;//fStr = fChr;
inserted = true;
//System.out.println("p.next.next = "+ p.next.next.GetS());
}
else if(copy.GetS().compareTo(fStr.GetS()) < 0)
{
System.out.println("(5)");
//System.out.println("1)p.next.next = "+ p.next.next.GetS());
copy.next = fStr;//ERROR ON THIS LINE
System.out.println("2)p.next.next = "+ p.next.next.GetS());
System.out.println("fChr.next: "+fChr.next.GetS());
fStr = copy;
System.out.println("3)p.next.next = "+ p.next.next.GetS());
inserted = true;
System.out.println("p = "+ p.GetS());
System.out.println("p.next = "+ p.next.GetS());
System.out.println("4)p.next.next = "+ p.next.next.GetS());
}
else if(fStr.next == null && fStr != null)
{
System.out.println("(6)");
fStr.next = copy;
inserted = true;
}
else
{
System.out.println("(7)");
pStr = fStr;
System.out.println("RIP (8)");
while(pStr.next != null && inserted == false)
{
System.out.println("(9)");
System.out.println("RIP");
if(copy.GetS().compareTo(pStr.next.GetS()) < 0)//if it goes between 2 nodes
{
System.out.println("(10)");
copy.next = pStr.next;
pStr.next = copy;
inserted = true;
}
else
{
System.out.println("(11)");
pStr = pStr.next;
}
if(pStr.next == null && inserted == false)// it goes at the end(not necessary bc of the (in order) part)
{
System.out.println("(12)");
pStr.next = copy;
}
}
}
repeat = JOptionPane.showInputDialog("Would you like to add a node [y/n]");
System.out.println("End of Loop");
}
System.out.println(fStr.GetS());
PrintMenu(fChr, fi, fd, fStr);// sends the user to the menu screen
}
From all of my print statements I have (what I think) found the problem. This code runs through twice and upon hitting "y" for the third time, prints "(3)" in an infinite loop. I have found that (say the input for the strings is "c" then "b") "p" is equal to "c", p.next is equal to "b" and p.next.next is equal to "c". So, p is in an infinite loop. I have no idea why it does this, I have a theory that it could be because the front(fChr) changes and then "p" points to it and is just kinda drug along. I also just realized that me trying to set "copy" equal to "NextNode" was unsuccessful and copy just holds the value inside p.next(which is NextNode). That seems correct, but when I try to put something else in, it doesn't work. I could be testing this incorrectly and in that case the setter is correct. Setting is one of the main problems that I seem to be having. I will try to answer as many questions as I can if anyone has any.
Also here is the object in case you would like to see it. Thank you for your time, any help will be appreciated. Please if possible try to keep it relatively simple this is a high school assignment and I am so close and am stumped on how to fix what is wrong. Also, you may have noticed, but I have to use private variables. I am not asking for someone to give me a program that works, I am just asking if you know why what is going wrong is happening and if you know how to fix it. Thank you from the bottom of my heart!
import javax.swing.JOptionPane;
public class list1
{
private int i;
private String s;
private double d;
private String ss = null;
private int ii = 0;
private double dd = 0.0;
list1 next = null;
public list1()
{
String str;
s=JOptionPane.showInputDialog("Enter a String");
String temp =JOptionPane.showInputDialog("Enter an Integer");
i = Integer.parseInt(temp);
String temp2 =JOptionPane.showInputDialog("Enter a Double");
d = Double.parseDouble(temp2);
}
public double GetD()
{
return d;
}
public String GetS()
{
return s;
}
public int GetI()
{
return i;
}
public void SetS(String x)
{
ss = x;
}
public void SetI(int y)
{
ii = y;
}
public void SetD(double z)
{
dd = z;
}
}

Lists in Java - Adding values to their keys (HashMap or HashSet or other)

I want to sort my LineChart X axis in JavaFX. I have Dates(X axis) from DatePicker and their Values(Y axis), but there are for exaple four exactly the same dates and different values. What I want to do is that I need to check if date exist, and if yes, I want to add the value to that date. Sorry about my english.
Look at my Linechart.
The first date has three values. I want to add them.
here is my code:
void initLineChart()
{
//defining a series
XYChart.Series<String,Number> series = new XYChart.Series<String, Number>();
lineChart.setAxisSortingPolicy(LineChart.SortingPolicy.X_AXIS);
String date = new String();
int numb;
String value = new String();;
ShowDreamHistoryController.save();
ShowDreamHistoryController.loadDreamAtStart();
for (int i = 0; i < ShowDreamHistoryController.listDreams.size(); i++) {
date = ShowDreamHistoryController.listDreams.get(i).getDate().toString();
value = ShowDreamHistoryController.listDreams.get(i).getHours();
if(value != null)
{
numb = Integer.valueOf(value);
series.getData().add(new XYChart.Data<String,Number>(date, numb));
}
}//for
// System.out.println(datesOnes);
lineChart.getData().add(series);
}
Check if the date exists in series and if it does, remove that index and add to it.
int indexExist = existAt(series,date);
if(indexExist < 0){ // if the date does not exist
series.getData().add(new XYChart.Data<String, Number>(date, numb));
} else { //if the date exists
int curVal = series.getData().get(indexExist).getYValue().intValue();
//get the current value stored in that date
series.getData().remove(indexExist);
// remove the index
series.getData().add(indexExist, new XYChart.Data<String,Number>(date, curVal + value));
// add to that index ( current value + value )
}
Then we would have a function that looks for the index.
/*
Loop through "SERIES" and return the position of the string
-1 if it doesn't exist.
*/
public int existAt(XYChart.Series <String, Number> series, String date){
for(int i=0; i<series.getData().size(); i++){
if(series.getData().get(i).getXValue().equals(date)){
return i;
}
}
return -1;
}

Hashtable key within integer interval

I don't know if this is possible but i'm trying to make an Hashtable of where Interval is a class with 2 integer / long values, a start and an end and i wanted to make something like this:
Hashtable<Interval, WhateverObject> test = new Hashtable<Interval, WhateverObject>();
test.put(new Interval(100, 200), new WhateverObject());
test.get(new Interval(150, 150)) // returns the new WhateverObject i created above because 150 is betwwen 100 and 200
test.get(new Interval(250, 250)) // doesn't find the value because there is no key that contains 250 in it's interval
So basically what i want is that a key between a range of values in an Interval object give the correspondent WhateverObject. I know i have to override equals() and hashcode() in the interval object, the main problem i think is to somehow have all the values between 100 and 200 (in this specific example) to give the same hash.
Any ideias if this is possible?
Thanks
No need to reinvent the wheel, use a NavigableMap. Example Code:
final NavigableMap<Integer, String> map = new TreeMap<Integer, String>();
map.put(0, "Cry Baby");
map.put(6, "School Time");
map.put(16, "Got a car yet?");
map.put(21, "Tequila anyone?");
map.put(45, "Time to buy a corvette");
System.out.println(map.floorEntry(3).getValue());
System.out.println(map.floorEntry(10).getValue());
System.out.println(map.floorEntry(18).getValue());
Output:
Cry Baby
School Time
Got a car yet?
You could use an IntervalTree. Here's one I made earlier.
public class IntervalTree<T extends IntervalTree.Interval> {
// My intervals.
private final List<T> intervals;
// My center value. All my intervals contain this center.
private final long center;
// My interval range.
private final long lBound;
private final long uBound;
// My left tree. All intervals that end below my center.
private final IntervalTree<T> left;
// My right tree. All intervals that start above my center.
private final IntervalTree<T> right;
public IntervalTree(List<T> intervals) {
if (intervals == null) {
throw new NullPointerException();
}
// Initially, my root contains all intervals.
this.intervals = intervals;
// Find my center.
center = findCenter();
/*
* Builds lefts out of all intervals that end below my center.
* Builds rights out of all intervals that start above my center.
* What remains contains all the intervals that contain my center.
*/
// Lefts contains all intervals that end below my center point.
final List<T> lefts = new ArrayList<T>();
// Rights contains all intervals that start above my center point.
final List<T> rights = new ArrayList<T>();
long uB = Long.MIN_VALUE;
long lB = Long.MAX_VALUE;
for (T i : intervals) {
long start = i.getStart();
long end = i.getEnd();
if (end < center) {
lefts.add(i);
} else if (start > center) {
rights.add(i);
} else {
// One of mine.
lB = Math.min(lB, start);
uB = Math.max(uB, end);
}
}
// Remove all those not mine.
intervals.removeAll(lefts);
intervals.removeAll(rights);
uBound = uB;
lBound = lB;
// Build the subtrees.
left = lefts.size() > 0 ? new IntervalTree<T>(lefts) : null;
right = rights.size() > 0 ? new IntervalTree<T>(rights) : null;
// Build my ascending and descending arrays.
/** #todo Build my ascending and descending arrays. */
}
/*
* Returns a list of all intervals containing the point.
*/
List<T> query(long point) {
// Check my range.
if (point >= lBound) {
if (point <= uBound) {
// In my range but remember, there may also be contributors from left or right.
List<T> found = new ArrayList<T>();
// Gather all intersecting ones.
// Could be made faster (perhaps) by holding two sorted lists by start and end.
for (T i : intervals) {
if (i.getStart() <= point && point <= i.getEnd()) {
found.add(i);
}
}
// Gather others.
if (point < center && left != null) {
found.addAll(left.query(point));
}
if (point > center && right != null) {
found.addAll(right.query(point));
}
return found;
} else {
// To right.
return right != null ? right.query(point) : Collections.<T>emptyList();
}
} else {
// To left.
return left != null ? left.query(point) : Collections.<T>emptyList();
}
}
private long findCenter() {
//return average();
return median();
}
protected long median() {
// Choose the median of all centers. Could choose just ends etc or anything.
long[] points = new long[intervals.size()];
int x = 0;
for (T i : intervals) {
// Take the mid point.
points[x++] = (i.getStart() + i.getEnd()) / 2;
}
Arrays.sort(points);
return points[points.length / 2];
}
/*
* What an interval looks like.
*/
public interface Interval {
public long getStart();
public long getEnd();
}
/*
* A simple implemementation of an interval.
*/
public static class SimpleInterval implements Interval {
private final long start;
private final long end;
public SimpleInterval(long start, long end) {
this.start = start;
this.end = end;
}
public long getStart() {
return start;
}
public long getEnd() {
return end;
}
#Override
public String toString() {
return "{" + start + "," + end + "}";
}
}
}
A naive HashTable is the wrong solution here. Overriding the equals() method doesn't do you any good because the HashTable compares a key entry by the hash code first, NOT the equals() method. The equals() method is only checked AFTER the hash code is matched.
It's easy to make a hash function on your interval object, but it's much more difficult to make one that would yield the same hashcode for all possible intervals that would be within another interval. Overriding the get() method (such as here https://stackoverflow.com/a/11189075/1261844) for a HashTable completely negates the advantages of a HashTable, which is very fast lookup times. At the point where you are scanning through each member of a HashTable, then you know you are using the HashTable incorrectly.
I'd say that Using java map for range searches and https://stackoverflow.com/a/11189080/1261844 are better solutions, but a HashTable is simply not the way to go about this.
I think implementing a specialized get-method would be much easier.
The new method can be part of a map-wrapper-class.
The key-class: (interval is [lower;upper[ )
public class Interval {
private int upper;
private int lower;
public Interval(int upper, int lower) {
this.upper = upper;
this.lower = lower;
}
public boolean contains(int i) {
return i < upper && i >= lower;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Interval other = (Interval) obj;
if (this.upper != other.upper) {
return false;
}
if (this.lower != other.lower) {
return false;
}
return true;
}
#Override
public int hashCode() {
int hash = 5;
hash = 61 * hash + this.upper;
hash = 61 * hash + this.lower;
return hash;
}
}
The Map-class:
public class IntervalMap<T> extends HashMap<Interval, T> {
public T get(int key) {
for (Interval iv : keySet()) {
if (iv.contains(key)) {
return super.get(iv);
}
}
return null;
}
}
This is just an example and can surely be optimized, and there are a few flaws as well:
For Example if Intervals overlap, there's no garantee to know which Interval will be used for lookup and Intervals are not garanteed to not overlap!
OldCurmudgeon's solution works perfectly for me, but is very slow to initialise (took 20 mins for 70k entries).
If you know your incoming list of items is already ordered (ascending) and has only non overlapping intervals, you can make it initialise in milliseconds by adding and using the following constructor:
public IntervalTree(List<T> intervals, boolean constructorFlagToIndicateOrderedNonOverlappingIntervals) {
if (intervals == null) throw new NullPointerException();
int centerPoint = intervals.size() / 2;
T centerInterval = intervals.get(centerPoint);
this.intervals = new ArrayList<T>();
this.intervals.add(centerInterval);
this.uBound = centerInterval.getEnd();
this.lBound = centerInterval.getStart();
this.center = (this.uBound + this.lBound) / 2;
List<T> toTheLeft = centerPoint < 1 ? Collections.<T>emptyList() : intervals.subList(0, centerPoint);
this.left = toTheLeft.isEmpty() ? null : new IntervalTree<T>(toTheLeft, true);
List<T> toTheRight = centerPoint >= intervals.size() ? Collections.<T>emptyList() : intervals.subList(centerPoint+1, intervals.size());
this.right = toTheRight.isEmpty() ? null : new IntervalTree<T>(toTheRight, true);
}
This depends on your hashCode implementation. You may have two Objects with the same hashCode value.
Please use eclipse to generate a hashCode method for your class (no point to re-invent the wheel
For Hastable or HashMap to work as expected it's not only a equal hashcode, but also the equals method must return true. What you are requesting is that Interval(x, y).equals(Interval(m, n)) for m, n within x,y. As this must be true for any overlapping living instance of Interval, the class has to record all of them and needs to implement what you are trying to achieve, indeed.
So in short the answer is no.
The Google guava library is planning to offer a RangeSet and Map: guava RangeSet
For reasonable small ranges an easy approach would be to specialize HashMap by putting and getting the indivual values of the intervals.

Categories