0

I have a ScenarioGenerator class to generate the Scenario. And in the Audit class, I set the function to decide how many scenarios to be generated and wanted to print out the occurrence of each enum type (Gender in this case).

I've referred to Counting an Occurrence in an Array (Java)

I used the frequency method to count the occurrence, but when there are many scenarios generated, I don't know how to aggregate the data. What I've tried was:

  1. Generate the scenarios and add each scenario in the ArrayList
  2. For each scenario, I get the passenger ArrayList, and save their attributes in different collections.
  3. For each collection, print out its value and the count.

I can simply do like this:

int maleCount = Collections.frequency(genderCollection, Gender.MALE);
System.out.println(Gender.MALE.toString().toLowerCase() + ":" +maleCount);

However, if I have more enums and attributes, this method becomes lengthy and inefficient. Is there any way to deal with this?

Here is part of my Audit class:

public class Audit {

private Scenario scenario = new Scenario();
private ScenarioGenerator scenarioGenerator = new ScenarioGenerator();
private Person person = new Person();

private String auditType;
private int nubmerOfSimulation;

public enum Gender {
    MALE, FEMALE, UNKNOWN;
}

public Audit() {

}

// create a specific number of random scenarios
// the concept similar to gamePlayed and gameWon in the last project
public void run(int runs) {
    this.nubmerOfSimulation = runs;
    ArrayList<Scenario> scenarios = new ArrayList<Scenario>();//create a arrayList to store each scenario

    for (int i = 0; i < runs; i++) {
        Scenario singleScenario = scenarioGenerator.generate();
        scenarios.add(singleScenario); // save each scenario into a scenario arrayList
    }
    survialCalculator(scenarios);        
}

public int survialCalculator(ArrayList<Scenario> scenarios) {
    //person attribute arrayList
    ArrayList<Gender> genderCollection = new ArrayList<Gender>();

    for (Scenario scenario : scenarios) { // for each scenario, getting its passengers and pedestrians
        ArrayList<Character> passengers =  scenario.getPassengers();
        for (Character passenger : passengers) {
            if (passenger instanceof Person) {
                Gender gender = ((Person) passenger).getGender();
                //System.out.println(gender);
                genderCollection.add(gender);    
        }
    }

    //try to print out the elements in the collection and its frequency, but failed
    for(Gender genderElement : genderCollection) {
        int genderCount = Collections.frequency(genderCollection, genderElement);
        System.out.println(genderElement.toString().toLowerCase()+ ":" + genderCount);
    }

    return 1;

}

Here is part of my ScenarioGenerator:

public class ScenarioGenerator {


private Person person = new Person();
private Random random = new Random();   

private int passengerCountMinimum;
private int passengerCountMaximum;

private int pedestrianCountMininum;
private int pedestrianCountMaximum;

private ArrayList<Character> passengers = new ArrayList<Character>();
private ArrayList<Character> pedestrians = new ArrayList<Character>();

public Person getRandomPerson() {
    //need age, gender, bodyType, profession, pregnancy
    int age = random.nextInt(100);
    int profession = random.nextInt(person.getProfessionEnumLength());
    int gender = random.nextInt(person.getGenderEnumLength());
    int bodyType = random.nextInt(person.getBodyTypeEnumLength());
    int pregnancy = random.nextInt(2);

    Person people = new Person(age, 
                               Profession.values()[profession], 
                               Gender.values()[gender],
                               BodyType.values()[bodyType], 
                               pregnancy == 1 ? true : false);
    return people;
}

public Animal getRandomAnimal() {
    //species, isPet
    int age = random.nextInt(100);
    int gender = random.nextInt(person.getGenderEnumLength());
    int bodyType = random.nextInt(person.getBodyTypeEnumLength());
    boolean isPet = random.nextBoolean();


    String [] species = {"cat", "dog"};
    int idx = random.nextInt(species.length);
    String pickSpecies = species[idx];


    Animal creature = new Animal(age, Gender.values()[gender], BodyType.values()[bodyType] , pickSpecies); 
    creature.setIsPet(isPet);

    return creature;       
}
//getters and setter of min and max numbers of passengers and pedestrians
public Scenario generate() {

    //random number of passengers and pedestrians with random characteristics
    //randomly red light or green light
    //random condition "You" in the car
    //abide by the minimum and maximum counts from above setters

    //get random numbers abide by the setters
    int numberOfPassengers = ThreadLocalRandom.current().nextInt(getPassengerCountMin(), getPassengerCountMax()+1);
    int numberOfPedestrains =ThreadLocalRandom.current().nextInt(getPedestrianCountMin(), getPedestrianCountMax()+1);

    boolean legalCrossing = random.nextBoolean();

    //generate the number from the total numbers of passenger and pedestrians
    int numberOfPersonPassenger = ThreadLocalRandom.current().nextInt(0, numberOfPassengers+1);
    int numberOfAnimalPassenger = numberOfPassengers - numberOfPersonPassenger;

    int numberOfPersonPedestrian = ThreadLocalRandom.current().nextInt(0, numberOfPedestrains+1);
    int numberOfAnimalPedestrian = numberOfPedestrains - numberOfPersonPedestrian;

    //generate the number of person passengers
    for (int i = numberOfPersonPassenger; i > 0; i--) {
        Person person = getRandomPerson();
        passengers.add(person);
    }

    //remaining of the number of passengers should be animals
    //no matter it is pet of not
    for (int i = numberOfAnimalPassenger; i > 0; i--) {
        Animal animal = getRandomAnimal();
        passengers.add(animal);
    }

    for (int i = numberOfPersonPedestrian; i > 0; i--) {
        Person person = getRandomPerson();
        pedestrians.add(person);
    }

    for (int i =numberOfAnimalPedestrian; i > 0; i--) {
        Animal animal = getRandomAnimal();
        pedestrians.add(animal);
    }
    Scenario scenario = new Scenario(passengers, pedestrians, legalCrossing);

 return scenario;

}

Here is part of my Scenario class:

public class Scenario {
private Random random;

private ArrayList<Character> passenagers = new ArrayList<Character>();
private ArrayList<Character> pedestrians = new ArrayList<Character>();

private boolean legalCrossing;


public Scenario() {

}

public Scenario(ArrayList<Character> passengers, ArrayList<Character> pedestrians, boolean isLegalCrossing) {
    this.passenagers = passengers;
    this.pedestrians = pedestrians;
    this.legalCrossing = isLegalCrossing;
}
//getters and setters

The main class is to call the method:

public static void main(String[] args) throws Exception {

    ethicalEngine.generate();

}
public void generate() { 
    Audit audit = new Audit();
    audit.run(5); 
}
Woden
  • 1,054
  • 2
  • 13
  • 26

2 Answers2

1

You might consider using the Guava Multiset. As Stated here this data structure is more efficent when you have more attributes to count as the access to the number lies most of the time in O(1).

Tim
  • 75
  • 5
  • Thank you, sir. What if I can't use the library? Is there any way? – Woden Jun 06 '20 at 11:29
  • 1
    You could try to use a `HashMap` instead. Check if it already contains the enum and then increase the count. To check wether a key is already part of the map is averagely in O(1). Same goes for accessing the map. You can also try to implement your own MultiSet based of [the code](https://github.com/google/guava/blob/master/guava/src/com/google/common/collect/Multiset.java) form the Guava project. – Tim Jun 06 '20 at 12:43
  • Thank you very much, I'll try. – Woden Jun 06 '20 at 12:53
1

You can use groupingBy stream operation on List<Gender> to get map of all gender type with count.

Map<Gender, Long> counted = genderCollection.stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

And print this way

for (Map.Entry<Gender, Long> item : counted.entrySet()) {
    System.out.println(item.getKey().toString()+ ":" + item.getValue());
}
Eklavya
  • 17,618
  • 4
  • 28
  • 57