代码之家  ›  专栏  ›  技术社区  ›  Igor

如何以适当的顺序收集和合并Java流中的不同对象?

  •  -5
  • Igor  · 技术社区  · 6 年前

    我有两个目标:

    String y = "Y"
    String r = "R"
    

    如何收集该值并将其与Java流合并以接收此行: "YYRYYRYYRYY" ?

    溪流可以是无止境的,但应该从 YY 并以结束 YY年 ,但每三个值应为 R

    3 回复  |  直到 6 年前
        1
  •  2
  •   Zabuzard Louis-Philippe Lebouthillier    6 年前

    有限序列

    假设您要创建一个有限的字符序列,其中包含 Y R , 随机 ,只需创建一些 next() 方法并重复调用它:

    public final class SequenceGenerator {
        private final String[] elements;
        private final Random rnd;
    
        public SequenceGenerator(Collection<String> elements) {
            this.elements = elements.toArray(new String[elements.size()]);
            rnd = new Random();
        }
    
        public String next() {
            return elements[rnd.nextInt(elements.length)];
        }
    
        public String generate(int amountOfElements) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < amountOfElements; i++) {
                sb.append(next());
            }
            return sb.toString();
        }
    }
    

    该类获取要从中提取的可能元素的集合及其 next 方法随机选择一例。这个 generate 方法重复调用它并附加绘制的元素。

    用法很简单:

    SequenceGenerator gen = new SequenceGenerator(List.of("Y", "R"));
    System.out.println(gen.generate(11));
    

    可能会打印以下内容:

    YYRYYRYYRYY
    

    源源不断

    您还可以很好地使用 Stream API在此创建无穷无尽的流:

    SequenceGenerator gen = new SequenceGenerator(List.of("Y", "R"));
    Stream<String> sequence = Stream.generate(gen::next);
    

    编辑: YY R

    正如您所说的,您希望流以 YY年 ,以及 R 在每三个位置,我们需要修改 下一个() 一点。首先,我们添加一个字段 int amount 跟踪电话。然后 下一个() 已修改为帐户 YY年 在开始和 R . 同样地 生成 必须修改以考虑 YY年 最后。流变量可以保持不变,因为它使用修改后的 下一个() 不需要解释 YY年 因为它是无穷无尽的。

    public final class SequenceGenerator {
        // ...
        private int amount;
    
        public SequenceGenerator(Collection<String> elements) {
            // ...
            amount = 0;
        }
    
        public String next() {
            // Start must be 'YY'
            if (amount == 0 || amount == 1) {
                amount++;
                return "Y";
            }
    
            // Every third must be 'R'
            if (amount % 3 == 0) {
                amount++;
                return "R";
            }
    
            // Pick a random element
            amount++;
            return elements[rnd.nextInt(elements.length)];
        }
    
        public String generate(int amountOfElements) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < amountOfElements - 2; i++) {
                sb.append(next());
            }
    
            // End must be 'YY'
            sb.append("YY");
    
            return sb.toString();
        }
    }
    

    实际上,我们还需要考虑另一个要求。的串联 YY年 对于强制 R 在每三个位置。所以对于 生成 这个 amountOfElements 必须比可除以的值大2 3 ,否则结果值无效。

    我们需要考虑边缘情况, 数量 必须至少为 5 ,每个较小的序列都无效。 YYRYY 是第一个有效序列。修改后的方法:

    public String generate(int amountOfElements) {
        if (amountOfElements < 5 || (amountOfElements - 2) % 3 != 0) {
            throw new IllegalArgumentException("Invalid sequence length");
        }
        // ...
    }
    
        2
  •  1
  •   kozmo    6 年前

    如果你想使用流,你必须这样做:

    final long iterateLimit = 20;
    final String sequence = "YYR";
    final String suffix = "YY";
    final String yyrString = Stream.generate(() -> sequence)
                                   .limit(iterateLimit)
                                   .collect(Collectors.joining())
                                   .concat(suffix);
    

    我提供生成 序列 “的” YYR年 “并添加 后缀 " YY年 “创建字符串后。

        3
  •  0
  •   Holger    6 年前

    你的需求中有一个矛盾,流可以是无止境的,但应该以YY结束。

    据我所见,你想要的只是重复的 Y , Y , R ,其结构如下

    String y = "Y";
    String r = "R";
    String[] toRepeat = { y, y, r };
    Stream.generate(() -> toRepeat).flatMap(Arrays::stream)
    

    所以你可以打印这个无休止的序列:

    Stream.generate(() -> toRepeat).flatMap(Arrays::stream)
          .forEach(System.out::println);
    

    要将其转换为以“yy”结尾的有限序列,请使用一个比可被三整除的数字小1的限制,例如,5、8、11、332等。

    然后,您可以将流收集/合并到 String :

    String[] toRepeat = { y, y, r };
    String seq = Stream.generate(() -> toRepeat).flatMap(Arrays::stream)
          .limit(11)
          .collect(Collectors.joining());
    System.out.println(seq);
    

    而不是 .collect(Collectors.joining()) ,您也可以使用 .reduce("", String::concat) ,但前者通常效率更高。

    另一种方法是迭代满足您需求的所有序列:

    Stream.iterate(y+y, s -> s+r+y+y)
        .forEach(System.out::println);
    

    这可用于查找第n个有效序列:

    Stream.iterate(y+y, s -> s+r+y+y)
        .skip(10)
        .findFirst()
        .ifPresent(System.out::println);