【问题标题】:How do I get a list of items from a subset of a list, based on the items in another list in Java?如何根据 Java 中另一个列表中的项目从列表的子集中获取项目列表?
【发布时间】:2020-05-06 12:21:56
【问题描述】:

我有一个List<String>,它代表另一个列表中的项目的 ID(可以重复),这是一个 List<Cheat>,其中每个 Cheat 都有一个字符串 ID 和一个 List<Integer> RNG。两者都有 Cheat 中的访问器方法。

我需要将此 ID 列表转换为我已为其提供 ID 的每个 Cheat 的 RNG 列表。

例如,我可以有 3 个秘籍:

1:{ID:1, RNG:{1,2,3}}
2:{ID:2, RNG{1,2}}
3:{ID:3, RNG:{1}}

以及以下 ID 的列表:

{3,1,1,2}.

我需要最终得到 {1,1,2,3,1,2,3,1,2} 的最终列表,即作弊 3 的 RNG,然后是作弊 1 的 RNG,然后再次是作弊1的RNG,最后是作弊2的RNG。

如果有人可以帮助我,将不胜感激。谢谢。

我尝试过但失败了:

ImmutableList<Integer> sequenceRngs = cheatIds.stream()
                                              .map(s -> cheats.stream()
                                                                .filter(cheat -> cheat.getId().equals(s))
                                                                .findFirst()
                                                                .map(cheat -> cheat.getRng()))
                                              .flatMap(cheat -> cheat.getRng())
                                              .collect(ListUtils.toImmutableList());

【问题讨论】:

  • 你能补充一下你目前尝试过的吗?

标签: java list functional-programming java-stream


【解决方案1】:

传递给 flatMap 的 lambda 应该返回 Stream,而不是 List。并且您应该处理流中没有此类元素的情况 - 即使您确定存在。应该这样做:

final ImmutableList<String> sequenceRngs = cheatIds.stream().flatMap(id ->
    cheats.stream().filter(cheat -> id.equals(cheat.getId()))
        .findAny().orElseThrow(IllegalStateException::new)
        .getRng().stream())
    .collect(ListUtils.toImmutableList());

另外,我建议将作弊列表转换为地图 - 这将简化代码并将搜索的复杂性从 O(n) 降低到 O(1)。

【讨论】:

    【解决方案2】:

    一种可能的解决方案:

    import java.util.List;
    import java.util.stream.Collectors;
    
    class Scratch {
    
        static class Cheat {
            int id;
            List<Integer> rng;
    
            public Cheat(int id, List<Integer> rng) {
                this.id = id;
                this.rng = rng;
            }
        }
    
        public static void main(String[] args) {
    
            List<Cheat> allCheats = List.of(
                    new Cheat(1, List.of(1,2,3)),
                    new Cheat(2, List.of(1,2)),
                    new Cheat(3, List.of(1))
            );
    
            List<Integer> result = List.of(3, 1, 1, 2).stream()
                    .flatMap(id -> allCheats.stream()
                            .filter(cheat -> cheat.id == id)
                            .findFirst().orElseThrow().rng.stream())
                    .collect(Collectors.toList());
    
            System.out.println(result);
    
        }
    }
    

    关键是使用 flatMap 将结果放在一个单一的——非嵌套的——Collection 中。

    【讨论】:

    • 注意:这每次都会为相同的id创建一个流,迭代allCheats,可以减少the other answer。例如对于输入中的1,1,它将迭代allCheats 两次。
    【解决方案3】:

    您可以通过以下步骤实现:

    1. 创建cheatId 与 RNG ids 关联的映射:

      Map<Integer, List<Integer>> map = cheats.stream()
              .collect(Collectors.toMap(Cheat::getId,
                      cheat -> cheat.getRng().stream().map(RNG::getId).collect(Collectors.toList())));
      
    2. 迭代作为输入提供的cheatIds,并从地图中获取相应的RNG ids以收集作为输出:

      List<Integer> output = cheatIds.stream()
              .flatMap(ch -> map.get(ch).stream())
              .collect(Collectors.toList());
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-04
      • 1970-01-01
      • 2020-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多