Sorting ArrayList of Objects

Hi. I’m having some trouble with sorting ArrayLists of Objects. I’m studying the Comprable interface but still have doubts on it’s implementation.
I’m doing a sketch that reads and compile local Covid-19 data. All my data are stored in an open .csv file that is stored on github. the csv files has for each row a timestamp, location(city/state), new cases, total cases, number of deaths. So far so good. I’m reading the tables, storing each entry for the designated place(city,state) and i get a time series visualization for each place.

How is my data stored.

I’ve built a single Object called Entry

class Entry {
  String timestamp;
  int y;
  int m;
  int d;
  int newCases;
  int totalCases;
  int numDeaths;
  
  Entry(String timestamp, int y, int m, int d, int nC, int tC, int nD) {
    this.timestamp=timestamp;
    this.y=y;
    this.m=m;
    this.d=d;
    newCases=nC;
    totalCases=tC;
    numDeaths=nD;
  }
  
    Entry(String timestamp, int y, int m, int d, int nC, int tC) {
    this.timestamp=timestamp;
    this.y=y;
    this.m=m;
    this.d=d;
    newCases=nC;
    totalCases=tC;
  }
}

and created two different objects, state and city. each object has it’s own ArrayList of entries and each entry is splitted in different ArrayLists for each data from the entries. below is the data handling parts of the state object, i haven’t placed the graphics handling below.

class Estado {
  ArrayList<Entry> entries;
  ArrayList<Integer> nCs;//new cases
  ArrayList<Integer> tCs;//total cases
  ArrayList<Integer> nDs;//num Deaths
  ArrayList<String> tSs;//timestamps

  int maxTC, maxNC, maxD;//max value for each data

  Estado(String sigla, String name, int id, PShape s) {
    entries=new ArrayList<Entry>();
    nCs=new ArrayList<Integer>();
    tCs=new ArrayList<Integer>();
    nDs=new ArrayList<Integer>();
    tSs=new ArrayList<String>();
    pg=createGraphics(graphW, graphH);
    this.s=s;

    maxTC=0;
    maxNC=0;
    maxD=0;

    this.sigla=sigla;
    this.name=name;
    this.id=id;
    addEntry("0", 0, 0, 0, 0, 0, 0);
  }

  @Override int compareTo(Estado other){
   return this.maxTC - other.maxTC; 
  }

 void addEntry(String ts, int y, int m, int d, int nC, int tC, int nD) {
    entries.add(new Entry(ts, y, m, d, nC, tC, nD));
  }

  void buildData() {
    cols=entries.size();
    colW=graphW/cols;

    for (Entry en : entries) {
      int n=en.newCases;
      nCs.add(new Integer(n));
      int t=en.totalCases;
      tCs.add(new Integer(t));
      int d=en.numDeaths;
      nDs.add(new Integer(d));
      String ts=en.d+"/"+en.m;
      tSs.add(new String(ts));
      if (t>maxTC) maxTC=t;
      if (n>maxNC) maxNC=n;
      if (d>maxD) maxD=d;
    }
  }
}

what i want to know is how to sort these objects in descending order accordingly to the desired visualization, total cases and numDeaths by state and top 20 infected cities without interferring with the original array?

tks in advance

1 Like
class Estado {
  ArrayList<Entry> entries;
  ArrayList<Integer> nCs;//new cases
  ArrayList<Integer> tCs;//total cases
  ArrayList<Integer> nDs;//num Deaths
  ArrayList<String> tSs;//timestamps

This is confusing because each Entry has a value for new cases, total cases and new deaths so what is the purpose of the last four arraylists?

i’ve created these lists in order to build the time series graphics and find each object max values. it’s used int the buidData and buidGraph functions
gr
don’t know if it’s redundant, but i’m acessing them

void buildGraph() {
    pg.beginDraw();
    pg.background(32);
    pg.noFill();

    //drawGrid
    for (int i=0; i<cols; i++) {
      float x=i*colW;
      pg.strokeWeight(1);
      pg.stroke(64);
      pg.line(x, 0, x, graphH);
      pg.fill(200);
      pg.noStroke();
      pg.textSize(8);
      pg.text(tSs.get(i), x, graphH);
    }

    //newCases
    pg.beginShape();
    pg.noFill();
    pg.strokeWeight(2);
    pg.stroke(#FF0000);

    for (int i=0; i<cols; i++) {
      float x=i*colW;
      int y=int(map(nCs.get(i), 0, maxNC, graphH, 0));
      pg.vertex(x, y);
    }
    pg.endShape();

    //totalCases
    pg.beginShape();
    pg.noFill();
    pg.stroke(#00FF00);
    for (int i=0; i<cols; i++) {
      float x=i*colW;
      int y=int(map(tCs.get(i), 0, maxTC, graphH, 0));
      pg.vertex(x, y);
    }
    pg.endShape();

    //numDeaths
    if (maxD>0) {
      pg.beginShape();
      pg.noFill();
      pg.stroke(#00FFFF);
      for (int i=0; i<cols; i++) {
        float x=i*colW;
        int y=int(map(nDs.get(i), 0, maxD, graphH, 0));
        pg.vertex(x, y);
      }
      pg.endShape();
    }
    pg.endDraw();
  }

here is a sort using comparator

see How can I sort JSON by ID?



// Import 
import java.util.Comparator;

// Main List  
JSONArray valuesArray1= new JSONArray();

// ----------------------------------------------------------------

void setup() {
  size(600, 600); 

  // build up test data 
  String[] species = { "Panthera pardus", "Equus zebra", "Capra hircus" };
  String[] names = {  "Leopard", "Zebra", "Goat" };

  for (int i = 0; i < species.length; i++) {

    JSONObject animal = new JSONObject();

    animal.setInt("id", i);
    animal.setString("species", species[i]);
    animal.setString("name", names[i]);

    valuesArray1.setJSONObject(i, animal);
  }
}

void draw() {
  // print, sort and print again 
  printlnJSONArray(valuesArray1);
  valuesArray1 = sort1();
  printlnJSONArray(valuesArray1);

  // halt
  noLoop();
} //

// ----------------------------------------------------------------

void printlnJSONArray( JSONArray values ) {
  
  println ("-------------------\n"
    +"printlnJSONArray says: "); 

  for (int i = 0; i < values.size(); i++) {

    JSONObject animal = values.getJSONObject(i); 

    int id = animal.getInt("id");
    String species = animal.getString("species");
    String name = animal.getString("name");

    println(id + ", " + species + ", " + name);
  }
}

// ----------------------------------------------------------------

JSONArray sort1() {

  // load objects into a List (ArrayList, etc)
  ArrayList<JSONObject> myobjs = new ArrayList<JSONObject>(); 

  for (int i = 0; i < valuesArray1.size(); i++) {
    JSONObject currentArticle = valuesArray1.getJSONObject(i); 
    myobjs.add(currentArticle);
  }

  // sort the new list
  myobjs.sort(new JSONComparator());

  // create an array to put the sorted list in
  JSONArray jsonSorted = new JSONArray();

  // append the objects in order
  for (JSONObject obj : myobjs) {
    jsonSorted.append(obj);
  }

  // now your sorted list of objects are loaded in a JSONArray
  return jsonSorted;
  //
}//func 

// ======================================================================================================================

// Tool takes care of comparator(s): needed for sorting the List 

// we can either sort like in a lexicon (ABCD... -> 0 111 22 3 4444 56) or numeric (0 3 22 56 111....)  

// this will fail on very long IDs like 9923898494443; maybe using Long helps 

// sorting for the List 
class JSONComparator implements Comparator<JSONObject> {

  @Override
    public int compare (JSONObject a, JSONObject b) {

    // this will fail on very long IDs like 9923898494443; maybe using Long helps

    // The following notation is short for these if clauses:
    // if a<b return -1;
    //   if a==b return 0;
    //   else return 1;
    //return aIndex < bIndex ? -1 : 
    //  aIndex.equals(bIndex) ? 0 :
    //  1;

    String aIndex = a.getString("species");
    String bIndex = b.getString("species");

    return 
      aIndex.compareToIgnoreCase( bIndex ); // we sort like in a lexicon (ABCD...) 
    //
  }
}//class
//
2 Likes

Okay, so you have an Estado and a Ciudade Cidade class, and each of them contains an ArrayList<Entry>. Is that right?

When you say

i want to know is how to sort these objects in descending order accordingly to the desired visualization

Does this mean that you have an ArrayList<Estado> that you want to sort? And you want them sorted by new cases from… the most recent entry, or a specific timestamp, or the largest historical entry, or…?

@quark is right that you can drop these:

  ArrayList<Integer> nCs;//new cases
  ArrayList<Integer> tCs;//total cases
  ArrayList<Integer> nDs;//num Deaths
  ArrayList<String> tSs;//timestamps

The idea here will be to implement Comparators.

ArrayList<Entry> myEntries;
Comparator<Entry> entryCompByNew;
Comparator<Entry> entryCompByTotal;
Comparator<Entry> entryCompByDeaths;
Comparator<Entry> entryCompByTime;

myEntries.sort(entryCompByNew);

Then for Estados, the same thing:

Comparator<Estado> estadoCompByLatestNew;
Comparator<Estado> estadoCompByLatestTotal;
Comparator<Estado> estadoCompByLatestDeaths;
Comparator<Estado> estadoCompByTopNew;
Comparator<Estado> estadoCompByTopTotal;
Comparator<Estado> estadoCompByTopDeaths;

Notice that Total and Time are redundant sort orders unless for Entries unless estimates are ever revised down – and that time is probably preferred. Similarly TopTotal etc. is redundant for Estado.

By “numDeaths” in an Entry, do you mean in a day / unit of time, or do you mean the cumulative total deaths?

1 Like

thank all of you for the replies. i expect my doubts are well explained below.

i’ve already dumped the ArrayLists as sugested by @quark , i’m working directy with the entries ArrayList.

Does this mean that you have an ArrayList<Estado> that you want to sort? And you want them sorted by new cases from… the most recent entry, or a specific timestamp, or the largest historical entry, or…?

yes, i have an ArrayList<Estado> and an ArrayList<Cidade> in my main function. Right now I want the totalCases and numDeaths sorted for by max numbers for each day. I can do the daily visualizations right now but it’s not sorted. I have these functions pieChartStateCases and pieChartStateDeaths that do what is needed now without sorting. it’s just placing the sate sequences.

By “numDeaths” in an Entry, do you mean in a day / unit of time, or do you mean the cumulative total deaths?

My tables only have cumulative death data. I could implement daily difference calculator, but this will be in the next iteraction, as well as calculating the PPM.

all my sortings happens in the main function. they are called in the pieCharts functions. I kinda understand the implementation but did not fully grasped it. reading some documentation and seeing some examples still have doubts:

1.These comparators are ‘similar’ to ArrayLists? are they different data structures that use the original data without ‘destroying’ it or they do destroy? Because in my case, i need to keep them ‘safe’ because thay are already built cronologically.

  1. Do i place these comparators in the main function or in the State/City Object/
Comparator<Entry> entryCompByNew;
Comparator<Entry> entryCompByTotal;
Comparator<Entry> entryCompByDeaths;
  1. where do i call the sorting? in the setup, for this new data structure that i think should be
Comparator<Estado>compTotalCases;
Comparator<Estado>compTotalDeaths;
Comparator<Cidade>compTotalCases;

My main function concerning the handling of data

PGraphics pie1, pie2;
Table estado;//table with all states
Table cidade;//table with all cities
Table tabelaHistorico;// online table with all state data
Table tabslaHistoricoCidades; //online table with all city data

ArrayList<Estado> estados; //all states
Estado e;  //state that's being seen
ArrayList<Cidade> cidades; //all cities
Cidade c; //city that's being seen
ArrayList<Cidade> activeCities; //infected cities

in setup, i initialize the arraylists, build each state and city object and call all the functions to scrap the data dump and place the right data in the right object. that’s working fine by now.
also by key commands i toggle state/city view, horizontal keys iterate the visualization for each state/city and vertical key change daily visualization.

as i pointed above in my reply to @jeremydouglass, i don’s want to use a ‘destructive’ sort, because the original has many uses in the visualization process, but need to create a new data structure to place the sorted data

You can clone() it: Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/util/ArrayList.html#clone()

Before using sort() on it: Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html#sort(java.util.Comparator)

W/ a Comparator: Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/util/Comparator.html#compare(T,T)

1 Like

No. A Comparator is like a scale with two trays that takes two objects.

:balance_scale:

An ArrayList has a method .sort(). So you say “sort all these apples by weight” or “sort all these cars by hue” or “sort all these events by date” – and you hand the sort function a scale to work with, your Comparator. The Comparator takes just two apples and returns 0 if they are equal, or a negative or positive number if the first or second is greater. sort() algorithm can then use this to sort all the apples.

Same thing with Events. A Comparator compares two, and reports the order – by most new cases, for example. Or by total, etc. Pass a Comparator to ArrayList sort() and it sorts all Events.

Same thing for Estado. A Comparator could compare by anything – for example, the value of “new” in the most recent event of an Estado – and return which of two Estados has more. The comparator then used by ArrayList estados.sort() to sort the whole list.

Also note that sorting isn’t destructive if you can sort back.

2 Likes

coming back to close this thread. just to tell all of you that sorting by value is working fine, it was easier than it looks. people should make it look less scary, after all we are talking about a programming language for artists… LOL

below are some screens from the dashboard

hope you all are well and safe


4 Likes

Sorry, can you share the sort code please?

first, following documentation i’ve created this method in Estado class, since i wanted to see states with most cases first:

@Override int compareTo(Estado other) {
    return this.maxTC - other.maxTC;
  }

and in setup, i’ve sorted and reversed the ArrayLists after instatiated them all

Collections.sort(estados);
Collections.reverse(estados);
Collections.sort(activeCities);
Collections.reverse(activeCities);

i tend to believe that if i’d inverted the calculus in the method i wouldn’t need to reverse the sorted list. but since it’s working as i wanted, i’ve stopped to try that.

 return other.maxTC - this.maxTC ;

EDIT:
also, i’ve imported java collection library.

import java.util.Collections;
2 Likes