I'm working on a personal project to do with Pokemon. The fact that this program has to do with Pokemon isn't strictly important, but I think it will be easier to understand in Pokemon-related terms, so I'll explain it that way and anybody answering who doesn't know much about Pokemon can feel free to use more general terms if they'd want to:
I have a PokemonRecord
record which has 2 parameters for 2 PokemonTypes
. Any instance of PokemonRecord
can have either 1 or 2 types. If the PokemonRecord
has only 1 type, then type2 == null
. The following method's purpose is to take an array of PokemonTypes
and generate a list of all possible PokemonRecord
type combinations that will resist all of those given types. If you don't know what "resisting a type" means, then you can just think of this as a separate method which tests a condition and returns a boolean
.
This is a sample of the expected output:
Enter the name of a Pokemon type: water
Enter the name of a Pokemon type: ground
Enter the name of a Pokemon type: grass
Enter the name of a Pokemon type: done
The following type combinations resist all of [water, ground, grass]:
Grass
Normal & Grass
Grass & Ice
Grass & Fighting
Grass & Flying
Grass & Psychic
Grass & Bug
Grass & Ghost
Grass & Dragon
Grass & Dark
Grass & Fairy
Flying & Dragon
Bug & Dragon
Currently, my code works as intended; however, looking back, I'd like to write some things differently - in chess, when you find a good move, find a better one. I initially used a procedural for-loop approach in order to filter through the full list of PokemonTypes
and test every single combination of them:
public static List<PokemonRecord> genMonResToAll(PokemonTypes... types) {
List<PokemonTypes> allTypes = //List of possible PokemonTypes that this Pokemon can have (PokemonTypes that are not weak to any inputted PokemonTypes)
List<PokemonRecord> outputList = new ArrayList<>();
//Add any single-type Pokemon that resists all types
for(PokemonTypes type : allTypes)
if(new PokemonRecord(type).isResistantToAll(types))
outputList.add(new PokemonRecord(type));
//Add any multi-type Pokemon that resists all types
for (int i = 0; i < allTypes.size() - 1; i )
for (int j = i 1; j < allTypes.size(); j ) {
PokemonRecord testMon = new PokemonRecord(allTypes.get(i), allTypes.get(j));
if (testMon.isResistantToAll(types))
otuputList.add(testMon);
}
return outputList;
}
//The functionality of any specific `Pokemon` or `PokemonTypes` method used isn't relevant, they all work as intended.
I'm now trying to rewrite this code to be more declarative using the Stream
API. I was able to work out how to convert the first loop, the loop that adds single-type PokemonRecord
, to a Stream-based declarative statement. I'm having a much harder time wrapping my head around the second. My current code with the first loop refactored is:
public static List<PokemonRecord> genMonResToAll(PokemonTypes... types) {
List<PokemonTypes> allTypes = //List of possible PokemonTypes that this Pokemon can have (PokemonTypes that are not weak to any inputted PokemonTypes)
//Add any single-type Pokemon that resists all types
List<PokemonRecord> outputList= allTypes.stream()
.map(PokemonRecord::new)
.filter(x -> x.isResistantToAll(types))
.collect(Collectors.toList());
//Add any multi-type Pokemon that resists all types
for (int i = 0; i < allTypes.size() - 1; i )
for (int j = i 1; j < allTypes.size(); j ) {
PokemonRecord testMon = new PokemonRecord(allTypes.get(i), allTypes.get(j));
if (testMon.isResistantToAll(types))
otuputList.add(testMon);
}
return outputList;
}
//The functionality of any specific `Pokemon` or `PokemonTypes` method used isn't relevant, they all work as intended.
Any help is appreciated, feel free to ask if you need any clarification!
CodePudding user response:
Since PokemonRecord's are twodimensional, I don't think you should use streams. This is a better approach without streams:
- If you havn't done this already, this is a clean implementation of PokemonRecord, which guarantees that PokemonRecord(type1, type2) == PokemonRecord(type2, type1). Preventing any illegally non-equal objects this way is generally a good idea:
public record PokemonRecord(PokemonType type1, PokemonType type2) {
public PokemonRecord(PokemonType type1, PokemonType type2) {
if (type1 == type2) throw new IllegalArgumentException("Illegal type combination");
boolean order = type1 != null && (type2 == null || type1.compareTo(type2) < 0);
this.type1 = order ? type1 : type2;
this.type2 = order ? type2 : type1;
}
// your methods
}
- Now just add
null
to allTypes and staircase iterate over it (to get all possible combinations without duplicates):
public static List<PokemonRecord> genMonResToAll(PokemonType... types) {
List<PokemonType> allTypes = new ArrayList<>();
allTypes.add(null);
List<PokemonRecord> result = new ArrayList<>();
for (int s = allTypes.size(), i = 0; i < s; i ) for (int j = s - 1; j > i; j--) {
PokemonRecord record = new PokemonRecord(allTypes.get(i), allTypes.get(j));
if (record.isResistantToAll(types)) result.add(record);
}
return result;
}