通过使用 Java Stream API 组合来自 int 数组的唯一值来生成最小 int 值

Make minimum int value by combining unique values from int array using Java Stream API

我需要使用 Stream API 实现方法 int minValue(int[] values)。 该方法采用从 0 到 9 的整数数组,采用唯一值,并且 returns 是这些唯一数字的最小可能组合数。该数组不得转换为字符串。

示例 #1:输入 {1,2,3,3,2,3},返回值 - 123;

示例 #2:输入 {9,8},返回值 – 89。

我不知道如何使用 Stream API 实现每个流成员与值序列的乘法:如果我的排序流有值 (5, 3, 1) 我需要执行 5 * 1 + 3 * 10 + 1 * 100。如何使用 Stream API?

我的简单 for 循环解决方案如下:

    private static int minValue(int[] values) {
        int result = 0;
        int capacity = 1;

        int[] ints = Arrays.stream(values)
            .boxed()
            .distinct()
            .sorted(Collections.reverseOrder())
            .mapToInt(Integer::intValue).toArray();

        for (int i = 0; i < ints.length; i++) {
            result = result + ints[i] * capacity;
            capacity = capacity * 10;
        }

        return result;
    }

这里有一个方法:

    final int[] result = {0};
    Arrays.stream(values).boxed().distinct().sorted()
            .mapToInt(Integer::intValue).forEach(i -> result[0] = i + result[0] * 10);
    return result[0];

分别调用distinctsortreduce是一种方法:

int result = Arrays.stream(values)
            .distinct()                   // unique digits
            .sorted()                     // sorted digits (descending)
            .reduce((l, r) -> l * 10 + r) // shifts a digit and adds another one
            .orElseThrow();               // this is up to you

reduce 部分可能看起来很棘手,让我们在 1234 数字序列(已经区分并排序)上逐步检查它。

  1. l=1r=2 -> l * 10 + r 给出 10 + 2 = 12(新 l)。
  2. l=12r=3 -> l * 10 + r 给出 120 + 3 = 123(新 l
  3. l=123r=4 -> l * 10 + r 给出 1230 + 4 = 1234 (完成)

编辑: 正如 Holger 所指出的,这仅适用于顺序处理。以下解决方案将并行工作:

String result = Arrays.stream(values)
            .distinct()
            .sorted()
            .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
            .toString();
int intResult = Integer.parseInt(result);

这种重复计算可以转化为形式上正确的流操作,在

中已经证明

这些任务的区别只在于因子,你需要因子10,其他需要31。

但解决方法并不简单。您可以使用非关联函数编写一个简单但形式上错误的缩减操作,该函数仍然可以在当前实现的顺序执行中工作,但这将是对 Stream API 的滥用,并提出您希望获得什么的问题使用 Stream API.

Stream API 并不总能带来简单或有效的解决方案。这尤其适用于您的初始任务,即识别一个非常小的集合中的所有不同数字并将它们放在有序的中间结果中。

您可以将整个操作实现为

private static int minValue(int[] values) {
    int allDigits = 0;
    for(int i: values) allDigits |= 1 << i;

    int result = 0;
    for(int digit = 1; digit < 10; digit++)
        if((allDigits & (1 << digit)) != 0) result = result * 10 + digit;

    return result;
}

由于任务描述指出所有值都在 0..9 范围内,因此它们很容易适合具有 32 位的单个 int 值。当我们在遇到该数字时将第 0 位设置为第 9 位时,我们就会以一种本质上排序的方式获得信息。第二个循环只是探测每个数字的位,当数字出现时,它会执行一个 result = result * 10 + digit; 计算,类似于链接的问答,它在从最小数字到最大数字迭代时起作用,但从最大数字迭代到最小数字类似于你的方法也工作:

private static int minValue(int[] values) {
    int allDigits = 0;
    for(int i: values) allDigits |= 1 << i;

    int result = 0;
    for(int digit = 9, factor = 1; digit > 0; digit--)
        if((allDigits & (1 << digit)) != 0) {
            result = result + digit * factor;
            factor *= 10;
        }

    return result;
}