0

I currently have two ArrayLists that are not linked, though in order to run some of the methods I require, I believe I may need to nest one ArrayList within the object that fills the other ArrayList.

My two lists are:

public static ArrayList<Earthquake> quakeList = new ArrayList<>();
public static ArrayList<Observatory> obsList = new ArrayList<>();

where:

 public Earthquake(String n, String obs, double m, int y, double lat, double lng)    {        

    magnitude = m;
    setQuakeYear(y);
    setLatitude(lat);
    setLongitude(lng);
    setQuakeName(n);
    setObsName(obs);

}

and:

   public Observatory(String n, String c, int y, double a) {

    this.setObsname(n);
    this.setObscountry(c);
    this.setObsyear(y);
    this.setObsarea(a);
    avgMag = (averageEarthquake());

}

Which contain data on earthquakes and observatories respectively. My problem comes when trying to link the Earthquake data with a specific observatory, as I will need this functionality in order to return the Observatory with the largest AVERAGE earthquake magnitude on record.

I have a method to return the average Earthquake size at the observatory:

public double averageEarthquake() {

Observatory o = new Observatory();  
int i = 0;
double sum = 0.0;

for(Earthquake quake : rcdQuakes) {
    i++;
    sum += quake.magnitude;
}

o.avgMag = sum / i;
return sum / i; 

}

(rcdQuakes is a new ArrayList that am trying to add only earthquakes where obsName matches the Observatory.obsname)

Using the comparator as follows to order the obsList by averageEarthquake:

class ObsObsComp implements Comparator<Observatory>{

@Override
public int compare(Observatory o1, Observatory o2) {

     if (o1.averageEarthquake() > o2.averageEarthquake())  {

         return -1;

     }
     if (o1.averageEarthquake() < o2.averageEarthquake()) {
         return 1;
     }
     else {
         return 0;
     }      
}

}

The method I am calling to do this (in the IO main method) is:

public static Earthquake obsLargestAvg() {

    Collections.sort(obsList, new ObsObsComp());
    return obsList.get(0);
}   

In which I am hoping to order the obsList by highest averageEarthquake (avgMag in Observatory object). Of course, this isn't working right now. I am hope to find some way of connecting Earthquake.obsName and Observatory.obsname so that I can find the average of Observatory.o1 and compare it with the average of Observatory.o2, returning the obsname with the highest.

I apologise if this is confusing and will provide more info if required - Java is new to me and perhaps I have overcomplicated things a little. Any help will be greatly appreciated!

EDIT***

I have changed my code so that the Earthquake object takes Observatory object as a field rather than just obsName. So:

 public Earthquake(String n, Observatory obs, double m, int y, double lat, double lng)

I now need to populate rcdQuakes with a list of discrete Earthquakes of obs "o1" to run the average, assigning the average to the observatory Object itself. Are there any suggestions on how to populate the list with just earthquakes of a single observatory each time?

Liam C
  • 138
  • 10
  • maybe helps you: http://stackoverflow.com/questions/10213493/can-i-sort-two-lists-in-relation-to-each-other – DevOps85 Nov 05 '14 at 11:45
  • Why don't you put Observatory as a parameter of Earthquake, instead of String obsName? – vefthym Nov 05 '14 at 11:45
  • 1
    *"will provide more info if required"* - let's hope it's not required... – Daniel Nov 05 '14 at 11:45
  • show us the code where you populate rcdQuakes list. – SMA Nov 05 '14 at 11:55
  • "show us the code where you populate rcdQuakes list." - this is part of my problem. I'm unsure how to populate this list with only earthquakes related to an individual observatory. If I could do this, I believe the method call would be closer to working. Also, thanks for the suggestions - I'll look into them! – Liam C Nov 05 '14 at 12:10

1 Answers1

1

Based on the needs you stated here, why not use a

Map <Observatory,SortedSet<Earthquake>>

instead of two disjointed lists. Each earthquake list can use your comparator, so that, with the data populated in that structure, you can answer both the question of average for each observatory:

double avg = obs.get(myObs).stream.mapToDouble(Earthquake::getMagnitude).average().getAsDouble();

As well as have it sorted by default.

EDIT: Added more based on OPs comment:

The idea of using a SortedSet was based on your use of ObsObsComp in your example (perhaps you use this to display your earthquakes?). It doesn't need to sorted for the average algorithm I provided before to work - it was simply put there so that my alternative data structure didn't lose anything you had in your example.

There are always 100 different ways to implement your code, but for an example, one way to do this would be something like:

public class EarthquakeMonitor {

    private Map<Observatory, SortedSet<Earthquake>> quakes = new HashMap<>();

    public void reportQuake(Observatory obs, Earthquake quake) {
        if (!quakes.contains(obs)) {
            quakes.put(obs, new SortedSet<>(new ObsObsComp<Earthquake>());
        }
        quakes.get(obs).add(quake);
    }

    public double getAvgMagnitude (Observatory obs) {
        return getQuakes(obs).stream(mapToDouble(Earthquake::getMagnitude).average().getAsDouble();
    }


    /**
     * Pretty formats earthquakes per observatory.
     *
     *@return
     */
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Entry<Observatory, SortedSet<Earthquake>> entry : quakes.entrySet()) {
            sb.append("Observatory: ").append(entry.getKey().toString()).append("\n");
            for (Earthquake q : entry.getValues()) {
                sb.append("\t").append(q.toString());
            }
        }
    }
}

The approach with this example implementation is that EarthquakeMonitor encapsulates the logic for data storage and, optionally, formatting for simplified output(though, if formatting gets more complex, this should be encapsulated in its own class where the data from EarthquakeMonitor would be passed into...or, more functionally, formatting behavior passed in to a format method in the EarthquakeMonitor class).

Depending on your needs, EarthquakeMonitor can implement Map, to allow low-level access to the data structure, or (arguably more ideally) you can provide a higher-level API to the data based on the needs of your applications components that need to directly touch the data contained within the class (such as the getAvgMagnitude() method).

Steve Siebert
  • 1,874
  • 12
  • 18
  • Thanks for the suggestion! I'll look into implementing it. – Liam C Nov 05 '14 at 14:01
  • np, glad to have helped =) – Steve Siebert Nov 05 '14 at 16:21
  • In continuation of this... I have: `public static Map> eqMap = new HashMap<>();` populated with: `public static void mapQuakeToObs(String o, Earthquake e) { for (Observatory obs : obsList) { if(obs.getObsname().equals(o)) { Observatory x = obs; if (!eqMap.containsKey(o)) { eqMap.put(x, new ArrayList()); } eqMap.get(x).add(e); }}` How then can I created the SortedSet rather than the ArrayList I currently have? How would it need to be sorted? Unsure how to implement this! – Liam C Nov 05 '14 at 23:46
  • added example implementation to code above so code is formatted – Steve Siebert Nov 06 '14 at 06:32
  • Thanks Steve, this has been a huge help to me and hopefully to others too! – Liam C Nov 06 '14 at 11:58
  • Np, glad it helped, it was fun. – Steve Siebert Nov 08 '14 at 02:33