Java-如何在流中使用函数?

时间:2019-05-13 21:13:03

标签: java java-stream

最近,作为我研究的一部分,我们开始练习使用流解决Java问题。 在解决流的加/减或字符串/字符排序问题的定量问题时,相对清晰和易于理解,但是,使用流对我来说还不清楚一些复杂的问题。

例如,给定一组字符,我们必须为G-O / g-o范围内的每个字母打印逆信号,例如A变为Z,而字母b变为y。

例如,假设我们有集合'A','k','p'->操作之后,我们只会得到p。

使用简单的功能,可以解决以下问题:

public static char flipLetter(char c){
    int count = 7;
    if((int)c >= 72 && (int)c <= 78){
        for (int i = 72; i <= 78; i++) {
            if((int)c == i)
                return (char)((int)'Z' - count);
            count++;
        }
    }
    else{
        for (int i = 104; i <= 110; i++) {
            if((int)c == i)
                return (char)((int)'z' - count);
            count++;
        }
    }
    return c;
}
public static boolean isInRange(char c){
    return (((int)c >= 72 && (int)c <= 78) || ((int)c >= 104 && (int)c <= 110));

}
public static void inRange(char arr[]){
    for (int i = 0; i < arr.length; i++) {
        if(isInRange(arr[i])){
            System.out.print(flipLetter(arr[i])+" ");
        }
    }
}

我很乐意获得有关如何使用编写的代码来实现它以实现流或听到其他评论的帮助。

3 个答案:

答案 0 :(得分:1)

您可以这样做:

public static void inRange(char arr[]){
    IntStream.range(0, arr.length).mapToObj(i -> arr[i])
             .filter(letter -> isInRange(letter))
             .map(letter -> flipLetter(letter))
             .forEach(e -> System.out.print(e  + " "));
}

这将在传递的Stream中创建一个Array,过滤掉不在范围内的任何东西,对每个字母调用flipLetter方法,然后将每个字母打印出来

答案 1 :(得分:1)

您应该尝试编写将意图记录在案的代码给读者。因此,当任务包含条件“对于G-O / g-o范围内的每个字母”时,请勿编写类似

的代码
public static boolean isInRange(char c) {
    return (((int)c >= 72 && (int)c <= 78) || ((int)c >= 104 && (int)c <= 110));
}

public static boolean isInRange(char c) {
    return c > 'G' && c < 'O' || c > 'g' && c < 'o';
}

可以很明显地看出,您所谈论的范围是“ GO / go(专有)”而不是“ HN / hn(包括)”,而不是不必要地使用unicode / ascii数字而不是书写字符常量。该代码仍将执行相同的操作,但是现在,您可以在其中识别原始任务了。在任何一个变体中,类型转换都是不必要的。

如安德烈亚斯(Andreas)在this comment中所暗示的那样,您不需要计数循环即可找到差异,这就是负值的意思。因此flipLetter简化为

    if(c > 'G' && c < 'O') {
        return (char)('Z' - (c - 'A'));
    }
    if(c > 'G' && c < 'O') {
        return (char)('z' - (c - 'a'));
    }

但是当我们在检查范围之后使用它时,我们可以使用Character.isUpperCase(…)Character.isLowerCase(…)直接表示区分大小写的意图。

此外,基本算术规则告诉我们'Z' - (c - 'A')('Z' + 'A') - c相同,小写字母变体也是如此,因此这两种情况的代码仅在一个常数值上有所不同。

将这些发现放入Stream操作中会产生收益

public static void yourTask(char[] arr) {
    CharBuffer.wrap(arr).chars()
        .filter(c -> c >= 'H' && c <= 'N' || c >= 'h' && c <= 'n')
        .map(c -> (Character.isUpperCase(c)? 'A'+'Z': 'a'+'z') - c)
        .forEachOrdered(ch -> System.out.print((char)ch+" "));
}

(一个类似inRange的方法名称听起来像是一个测试,因此您应该提供一个更好的名称来描述该方法的实际作用)

请注意,它使用IntStream,因为Java中没有CharStream,这与Java一样好,无论如何,涉及char值的计算都是使用int完成的。仅在最后的打印语句中,我们需要执行强制转换为char的类型,以建立正确的语义,这会影响打印值的方式。

答案 2 :(得分:0)

inRange()方法的一种解决方案是:

public static void inRange(char[] arr) {
    IntStream.range(0, arr.length)
            .mapToObj(i -> arr[i])
            .filter(YourClass::isInRange)
            .map(YourClass::flipLetter)
            .forEach(c -> System.out.print(c + " "));
}

如果您希望结果为String,则可以使用以下方法:

public static void inRange(char[] arr) {
    String result = IntStream.range(0, arr.length)
            .mapToObj(i -> arr[i])
            .filter(YourClass::isInRange)
            .map(YourClass::flipLetter)
            .map(String::valueOf)
            .collect(Collectors.joining(" "));
    System.out.println(result);
}

如果您输入的是String,则只需将char[]传递给方法即可,然后使用string.chars()而不是IntStream.range(0, arr.length)