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<>();
}
}
}
Related
I want to generate some test data using this Java code:
#GetMapping("/volumes")
public ResponseEntity<List<DashboardDTO>> getProcessingVolumes() {
return ResponseEntity.ok(testDate());
}
public List<DashboardDTO> testDate() {
List<DashboardDTO> list = null;
for (int i = 0; i <= 10; i++) {
list = new ArrayList<>();
DashboardDTO obj = new DashboardDTO();
obj.setAmount(ThreadLocalRandom.current().nextInt(20, 500 + 1));
LocalDate localDate = LocalDate.now().minus(Period.ofDays((new Random().nextInt(365 * 70))));
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
obj.setDate(date);
obj.setNumber_of_transactions(ThreadLocalRandom.current().nextInt(300, 5000 + 1));
list.add(obj);
}
return list;
}
But when the code is run only one object is generated. Do you know where I'm wrong? I want to generate 10 test objects.
Here:
for (int i = 0; i <= 10; i++) {
list = new ArrayList<>();
You create a new result list during each loop. So the last loop creates another list for the last entry!
Simply move that line list = new ArrayList<>(); in front of the loop, so that it gets executed just once.
Your code creates 11 new lists, each one with one entry, and you return that last list object. Instead: create one list and add your 11 elements and then return that single list.
for (int i = 0; i <= 10; i++) {
list = new ArrayList<>(); //(Fix here)--> resetting your list everytime causing only single object to return.
Try to initialize only single time.
List<DashboardDTO> list = new ArrayList<>();
for (int i = 0; i <= 10; i++) {
DashboardDTO obj = new DashboardDTO();
obj.setAmount(ThreadLocalRandom.current().nextInt(20, 500 + 1));
LocalDate localDate = LocalDate.now().minus(Period.ofDays((new Random().nextInt(365 * 70))));
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
obj.setDate(date);
obj.setNumber_of_transactions(ThreadLocalRandom.current().nextInt(300, 5000 + 1));
list.add(obj);
}
return list;
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);
}
I am having problem creating LineChart it's just showing the last Line when I need to show all Lines can you please help? here's the code:
Collections.addAll(labels,` column);
dataSets = new ArrayList<ILineDataSet>();
for (monthlysales company : companieslist) {
entries.clear();
for (int j = 0; j < listofcompanies.Total.size(); j++) {
entries.add(new Entry(Float.parseFloat(listofcompanies.Total.get(j)), j));
}
setComp1 = new LineDataSet(entries, company.StoreName);
setComp1.setAxisDependency(YAxis.AxisDependency.LEFT);
setComp1.setColor(Color.BLUE);
dataSets.add(setComp1);
}
LineData data = new LineData(column,dataSets);
linechart.setData(data);
linechart.setDescription("Sales");
linechart.animateXY(5000,5000);
linechart.setPinchZoom(true);
linechart.setDoubleTapToZoomEnabled(true);
linechart.setDragDecelerationEnabled(true);
linechart.notifyDataSetChanged();
linechart.invalidate();
}
Thank you
This actually makes sense. You are adding data to the entries list, and then add it to the DataSet correctly. The problem is, you are clearing the entries list every time after you add it. you should use a separate list for each dataset.
replace the line:
entries.clear();
with
List<Entry> entries = new ArrayList<>();
it's now solved by creating a Function and call it as below :
**dataSets.add(createLineChart(company,company.StoreName,company.Total));**
data = new LineData(column,dataSets);
linechart.setData(data);
linechart.invalidate();
linechart.setDescription("Sales");
and this is the function:
private LineDataSet createLineChart(monthlysales company,String storeName,List<String> listofcompanies){
// LineData data=new LineData();
ArrayList<Entry> entries= new ArrayList<Entry>();
for (int j = 0; j < listofcompanies.size(); j++) {
entries.add(new Entry(Float.parseFloat(listofcompanies.get(j)),j));
linechart.notifyDataSetChanged();
}
Random rd = new Random();
setComp1 = new LineDataSet(entries,storeName);
setComp1.setColor(Color.argb(255,rd.nextInt(256),rd.nextInt(256),rd.nextInt(256)));
// LineData data =new LineData(labels,dataset);
return setComp1;
}
it seems that the LineDataSet was used the last time it was called displaying just one line.
I'm trying obtain all the names from one file and all the attendances from another then calculate the average attendance. I know the att bit in the calculation is completely wrong but I could not work it out.
{
ArrayList<Match> ourList = new ArrayList(teams);
ArrayList<Match> teamsAttendance = new ArrayList<Match>();
for (Match att : ourList)
{
if (att != null && att.getTeamName().equals(team.getName()))
{
teamsAttendance.add(att);
}
}
double attendance = 0; //start attendance as 0
for (int i = 0; i < att.length; i++)
{
attendance += att[i];
}
return attendance / att.length;
}
I am guessing that the Match class will have a team name and attendance(an array list). Just like getting the team name, there should be a get to get the attendance array list .Assuming this you can try the below approach:
{
ArrayList<Match> ourList = new ArrayList(teams);
ArrayList<Match> teamsAttendance = new ArrayList<Match>();
//to store the attendance mean for each team
ArrayList<double> teamAttendanceMean = new ArrayList<double>();
//to store the attendance values of team
ArrayList<double> tempAttendance= new ArrayList<double>();
//declare outside
double attendance = 0;
for (Match att : ourList)
{
if (att != null && att.getTeamName().equals(team.getName()))
{
teamsAttendance.add(att);
}
attendance = 0;// assign 0
tempAttendance = att.getTeamAttendance();
for (int i = 0; i < tempAttendance.size(); i++)
{
attendance += tempAttendance [i];
}
//storing the mean value
teamAttendanceMean.add(attendance/tempAttendance.size());
}
}
Let me know if any of my assumptions are wrong and also post information on the Match class if so.
Why this is not working? I am looping on a trxFifoArray List and passing its object items to result List. I need to split some amounts in 2 so I need to addFirst this 2 amount to result list. The amounts are in an arrayList [-9.0000, -6.0000]. So I loop the amount list to do the addFirst on result and the items are added but with same amount even the list has 2 different amount.
LinkedList<InvtQaTracer> trxFifoArray = new LinkedList<InvtQaTracer>();
LinkedList<InvtQaTracer> result = new LinkedList<InvtQaTracer>();
InvtQaTracer trx = new InvtQaTracer();
int trxDocoRef = 0;
for (int j = list.size() - 1; j >= 0; j--) {
trx = list.get(j);
System.out.printf("%12.4f %4s%10d %12s%n", trx.getTrxQty(), trx.getDocType(), trx.getOrdNo(), trx.getLocNo());
List<BigDecimal> auxAmounts = new ArrayList<BigDecimal>();
if (trx.getDocType().compareTo("OV") == 0
|| trx.getDocType().compareTo("XV") == 0) {
//Do something ...
} else {
BigDecimal auxAmount = BigDecimal.ZERO;
Boolean needRemove = false;
for (InvtQaTracer tFifo : trxFifoArray) {
if (trx.getDocType().compareTo("IT") == 0) {
auxAmounts.add(tFifo.getTrxQty().negate());
}
}
if (needRemove) {
Iterator<InvtQaTracer> iterator = trxFifoArray.iterator();
int count = 0;
while (iterator.hasNext()) {
InvtQaTracer iqt = iterator.next();
if (iqt.getTrxQty().compareTo(BigDecimal.ZERO) == 0) {
count++;
iterator.remove();
}
}
}
}
if (!auxAmounts.isEmpty()) {
for (BigDecimal asss : auxAmounts) {
System.out.println(asss);
trx.setTrxQty(asss);
result.addFirst(trx);
}
} else {
result.addFirst(trx);
}
for (InvtQaTracer invtQT : trxFifoArray) {
System.out.printf("%20s%2s%12.4f %10d %12s%10d%n", " ----------------> ", invtQT.getDocType(), invtQT.getTrxQty(), invtQT.getOrdNo(), invtQT.getLocNo(), invtQT.getDocNo());
}
}
This code add two records with -6.000000 value even it is printing out both of them. I hope you understand the code. Please Help!!!
Thanks.
Thanks for any help!
Am finding a problem in the code.
Code needs to be updated like this
if (!auxAmounts.isEmpty()) {
LinkedList<InvtQaTracer> result = new LinkedList<InvtQaTracer>();
//Updated Here
InvtQaTracer trx = null;
List<BigDecimal> auxAmounts = new ArrayList<BigDecimal>(); //[-9.000000, -6.000000]
for (BigDecimal asss : auxAmounts) {
System.out.println(asss);
//Updated Here
trx = new InvtQaTracer();
trx.setTrxQty(asss);
result.addFirst(trx);
}
} else {
result.addFirst(trx);
}
One more change identified is
inside the else loop needRemove value is set to false by default and below checking whether it is true in if loop. think this one can be removed.