1

This is a project I am working on for my intro to java class. My professor has already laid out the base code, and the point of the project is to work with HashMaps and ArrayLists in combination with arithmetic. Everything here is done by my professor so far except:

HashMap<String, Integer> typeAttack = new HashMap<String, Integer>();

I am also provided with a .csv file containing various statistics of a whole list of pokemon. Out of the objects that my professor has already passed into the ArrayList "pokemonList," I only need to consider the "type" and "attack" variable, as I need to figure out which type of pokemon in the whole .csv file averages to have the highest attack level.

int attack = Integer.parseInt(split[1]);

String type = split[5];

My question is very simple. How can I convert only a portion of the ArrayList, specifically the "attack" and "type" variables into my HashMap?

import java.util.*;
import java.io.*;

public class Project6 {

    public static void main(String[] args) throws IOException {
        ArrayList<Pokemon> pokemonList = collectPokemon(args[0]);


   HashMap<String, Integer> typeAttack = new HashMap<String, Integer>();


    }

    // Don't modify this method. If you get errors here, don't forget to add the filename
    // as a command line argument.
    public static ArrayList<Pokemon> collectPokemon(String filename) throws IOException {
        BufferedReader file = new BufferedReader(new FileReader(new File(filename)));
        ArrayList<Pokemon> pokemonList = new ArrayList<Pokemon>();
        file.readLine();
        while(file.ready()) {
            String line = file.readLine();
            String[] split = line.split(",");
            String name = split[0];
            int attack = Integer.parseInt(split[1]);
            int defense = Integer.parseInt(split[2]);
            double height = Double.parseDouble(split[3]);
            double weight = Double.parseDouble(split[6]);
            String type = split[5];
            Pokemon current = new Pokemon(name, attack, defense, height, weight, type);
            pokemonList.add(current);
        }
        return pokemonList;
    }
}

POKEMON CLASS

import java.util.*;

public class Pokemon {

    private String name;
    private int attack;
    private int defense;
    private double height;
    private double weight;
    private String type;

    public Pokemon(String inName, int inAttack, int inDefense, double inHeight, double inWeight, String inType) {
        name = inName;
        attack = inAttack;
        defense = inDefense;
        height = inHeight;
        weight = inWeight;
        type = inType;
    }

    public String getName() {
        return name;
    }

    public int getAttack() {
        return attack;
    }

    public int getDefense() {
        return defense;
    }

    public double getHeight() {
        return height;
    }

    public double getWeight() {
        return weight;
    }

    public String getType() {
        return type;
    }

    public String toString() {
        return "Pokemon: '" + name + "' Atk: " + attack + " Def: " + defense + " Ht: " + height + "m Wt: " + weight + "Kg Type: " + type;
    }
}
10
  • You loop through the list. For each pokemon in the list, you get its attack, adn you get its type (by calling the methods of the Pokemon class allowing to get this information). Then you do what you need to do (which you haven't said) to populate the map. Start by simpler problems. 1. loop through the list, and print each pokemon. 2. Loop through the list, and print the attack an type of each pokemon. Commented Nov 18, 2019 at 23:33
  • Can you show what the Pokemon class looks like Commented Nov 18, 2019 at 23:34
  • I don't understand, however... What is the method that he has created? It looks like it just sorts the elements of the .csv file into an ArrayList. How can I call this to obtain individual elements? Commented Nov 18, 2019 at 23:37
  • Also you don't need a map to figure out which pokemon has the highest attack level. You can do that with a simple loop Commented Nov 18, 2019 at 23:37
  • I am instructed to complete this by using HashMaps and ArrayLists instead of hardcoding with individual variables Commented Nov 18, 2019 at 23:39

1 Answer 1

1

You could try with a simple for each loop:

// Note the Map type change to Double!
HashMap<String, Double> typeToAvgAttack = new HashMap<String, Double>();

// Intermediate map to store list of all attack values per type
HashMap<String, List<Integer>> typeToAttack = new HashMap<String, List<Integer>>();

for (Pokemon pokemon: pokemonList) {
    String type = pokemon.getType();
    int attack = pokemon.getAttack();

    // the map is empty at start, we need to check for the keys (pokemon type) existance
    List<Integer> attackValues = typeToAttack.get(type); 
    if (attackValues == null) {
        typeToAttack.put(type, attackValues = new ArrayList());
    }
    attackValues.add(attack);
}

// Iterate over map keys to calculate the average
for (String type : typeToAttack.keySet()) {
    List<Integer> attackValues = typeToAttack.get(type);
    double average = calculateAverage(attackValues);
    typeToAvgAttack.put(type, average);
}

The helper function, copied from here:

public static double calculateAverage(List <Integer> values) {
    double sum = 0d;
    if(!values.isEmpty()) {
        for (Integer value: values) {
            sum += value;
        }
        return sum / values.size();
    }
    return sum;
}

Be aware though that this approach is neither optimal nor elegant. I'd prefer to use Stream API, but that may not be best suited for your current proficiency.

EDIT: I've adjusted the code not to use Java 8 methods.

Sign up to request clarification or add additional context in comments.

5 Comments

This helps. My current knowledge doesn't allow me to extend past your first enchanced for loop, but the two former lines help. Thank you.
I've updated the answer, trying to be more explicit. Let me know if there is still something unclear.
There is no reason to declare sum as boxed Integer instead of a straight-forward int. And instead of if (typeToAttack.containsKey(type)) { List<Integer> attackValues = typeToAttack.get(type); attackValues.add(attack); } else { List<Integer> attackValues = new ArrayList(); attackValues.add(attack); typeToAttack.put(type, attackValues); } you can use List<Integer> attackValues = typeToAttack.get(type); if(attackValues == null) typeToAttack.put(type, attackValues = new ArrayList()); attackValues.add(attack);
@Holger the second part I agree, editing the answer. The helper func I copied from the linked anwser. So maybe you should put the comment there, it has been awarded 64 points so far. There might be more appropriate people in the discussion than here ;). Pasting the link once more stackoverflow.com/questions/10791568/…
For the linked answer, the author changed int to Integer to fix the invocation of sum.doubleValue(). But you can replace the method invocation with a type cast, i.e. (double)sum instead, then it works smoothly with int sum; or just use double sum; in the first place. I left a comment there too, but there’s no reason to keep questionable code, just because its also in another answer…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.