使用 Streams 模拟嵌套 for 循环过滤

发布于 2025-01-17 10:03:29 字数 3346 浏览 0 评论 0原文

我正在研究一个与Pokemon一起工作的项目。

我有一个PokemonRecord记录,该记录具有2个参数,可用于2 PokemonTypesPokemonRecord的任何实例都可以具有1或2种类型。如果PokemonRecord只有1个类型,则type2 == null。以下方法的目的是采用pokemontypes的数组,并生成所有可能的pokemonRecord键入组合的列表,该组合可以抗拒所有这些给定类型。将“抵抗类型”视为一种单独的方法,该方法测试条件并返回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

目前,我的代码按预期运行;但是,回顾过去,我想以不同的方式写一些东西 - 在国际象棋中,当您找到一个好的举动时,找到一个更好的动作。我最初使用了一种程序式式方法,以通过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.

我现在试图使用<<<<<<代码>流 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.

I'm working on a project to do with Pokemon.

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. Think of "resisting a type" 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

最初的梦 2025-01-24 10:03:29

由于PokemonRecord是二维的,因此我认为您不应该使用流。这是一种没有流的更好方法:

  1. 如果您还没有这样做,那么这是PokemonRecord的干净实现,它可以保证PokemonRecord(type1,type2)== PokeMonRecord(Type2,type1)。以这种方式阻止任何非法的对象通常是一个好主意:
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
}
  1. 现在只需将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;
}

Since PokemonRecord's are twodimensional, I don't think you should use streams. This is a better approach without streams:

  1. 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
}
  1. 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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文