使用 Streams 模拟嵌套 for 循环过滤
Simulating nested for-loop filtering using Streams
我正在做一个与口袋妖怪有关的个人项目。这个程序与口袋妖怪有关的事实并不重要,但我认为用口袋妖怪相关的术语更容易理解,所以我会这样解释,任何对口袋妖怪不太了解的人都会回答如果他们愿意,可以随意使用更通用的术语:
我有一个 PokemonRecord
记录,它有 2 个参数用于 2 PokemonTypes
。 PokemonRecord
的任何实例都可以有 1 种或 2 种类型。如果 PokemonRecord
只有一种类型,则 type2 == null
。以下方法的目的是采用 PokemonTypes
的数组并生成所有可能的 PokemonRecord
类型组合的列表,这些组合将抵抗所有这些给定类型。如果您不知道“抵抗类型”是什么意思,那么您可以将其视为测试条件和 returns a boolean
.
的单独方法
这是预期输出的示例:
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
目前,我的代码按预期工作;然而,回过头来看,我想写一些不同的东西——在国际象棋中,当你找到一个好的着法时,找到一个更好的着法。我最初使用程序 for 循环方法来过滤 PokemonTypes
的完整列表并测试它们的每个组合:
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.
我现在正在尝试使用 Stream
API 重写此代码以使其更具声明性。我能够弄清楚如何将第一个循环(添加单一类型 PokemonRecord
的循环)转换为基于流的声明语句。我很难理解第二个问题。我当前重构第一个循环的代码是:
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.
感谢任何帮助,如果您需要任何说明,请随时询问!
由于 PokemonRecord 是二维的,我认为您不应该使用流。这是没有流的更好方法:
- 如果您还没有这样做,这是 PokemonRecord 的干净实现,它保证 PokemonRecord(type1, type2) == PokemonRecord(type2, type1)。以这种方式防止任何非法 non-equal 对象通常是个好主意:
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
}
- 现在只需将
null
添加到 allTypes 并对其进行楼梯迭代(以获得所有可能的组合而不会重复):
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;
}
我正在做一个与口袋妖怪有关的个人项目。这个程序与口袋妖怪有关的事实并不重要,但我认为用口袋妖怪相关的术语更容易理解,所以我会这样解释,任何对口袋妖怪不太了解的人都会回答如果他们愿意,可以随意使用更通用的术语:
我有一个 PokemonRecord
记录,它有 2 个参数用于 2 PokemonTypes
。 PokemonRecord
的任何实例都可以有 1 种或 2 种类型。如果 PokemonRecord
只有一种类型,则 type2 == null
。以下方法的目的是采用 PokemonTypes
的数组并生成所有可能的 PokemonRecord
类型组合的列表,这些组合将抵抗所有这些给定类型。如果您不知道“抵抗类型”是什么意思,那么您可以将其视为测试条件和 returns a boolean
.
这是预期输出的示例:
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
目前,我的代码按预期工作;然而,回过头来看,我想写一些不同的东西——在国际象棋中,当你找到一个好的着法时,找到一个更好的着法。我最初使用程序 for 循环方法来过滤 PokemonTypes
的完整列表并测试它们的每个组合:
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.
我现在正在尝试使用 Stream
API 重写此代码以使其更具声明性。我能够弄清楚如何将第一个循环(添加单一类型 PokemonRecord
的循环)转换为基于流的声明语句。我很难理解第二个问题。我当前重构第一个循环的代码是:
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.
感谢任何帮助,如果您需要任何说明,请随时询问!
由于 PokemonRecord 是二维的,我认为您不应该使用流。这是没有流的更好方法:
- 如果您还没有这样做,这是 PokemonRecord 的干净实现,它保证 PokemonRecord(type1, type2) == PokemonRecord(type2, type1)。以这种方式防止任何非法 non-equal 对象通常是个好主意:
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
}
- 现在只需将
null
添加到 allTypes 并对其进行楼梯迭代(以获得所有可能的组合而不会重复):
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;
}