For循环 - 类似于Python的range函数

38
我在想Java中是否有类似于Python的range函数。
range(4)

而且它会返回

[0,1,2,3]

这是一种简单的方法,用于增强循环。如果能在Java中实现这个,那将会大大简化for循环。这可行吗?


1
你尝试过自己写吗?这并不难。 - Barranka
这个问题中也有一些不错的解决方案:https://dev59.com/9HRC5IYBdhLWcg3wOeSB - OndroMih
有关任何 Comparable 的范围,请参见答案。 - c0der
9个回答

71

Java 8 (2014) 新增了 IntStream(类似于 apache commons 的 IntRange),因此现在不需要外部库。

import java.util.stream.IntStream; 

IntStream.range(0, 3).forEachOrdered(n -> {
    System.out.println(n);
});

forEach如果顺序不重要,也可以代替forEachOrdered使用。

IntStream.range(0, 3).parallel()可用于并行运行循环。


1
不错,但它对用于 lambda 表达式中的变量施加了限制,因此可能不太方便。 - Arthur

24

没有外部库,你可以做到以下几点。与当前已被接受的答案不同,它不会创建任何数组,在处理大型范围时将显著降低内存消耗。

创建一个如下的类:

class Range implements Iterable<Integer> {

    private int limit;

    public Range(int limit) {
        this.limit = limit;
    }

    @Override
    public Iterator<Integer> iterator() {
        final int max = limit;
        return new Iterator<Integer>() {

            private int current = 0;

            @Override
            public boolean hasNext() {
                return current < max;
            }

            @Override
            public Integer next() {
                if (hasNext()) {
                    return current++;   
                } else {
                    throw new NoSuchElementException("Range reached the end");
                }
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException("Can't remove values from a Range");
            }
        };
    }
}

您可以像这样简单地使用它:

    for (int i : new Range(5)) {
        System.out.println(i);
    }

您甚至可以重复使用它:

    Range range5 = new Range(5);

    for (int i : range5) {
        System.out.println(i);
    }
    for (int i : range5) {
        System.out.println(i);
    }

如下评论中Henry Keiter指出,我们可以在 Range 类(或任何其他位置)中添加以下方法:
public static Range range(int max) {
    return new Range(max);
}

然后,在其他课程中,我们可以:
import static package.name.Range.range;

并简单地调用

for (int i : range(5)) {
    System.out.println(i);
}

3
对于实际编写此迭代器,我给你点赞!有趣的是,你可以使用类似Python的语法通过一个简单的getter方法来进一步封装它:public static Range range(int max) { return new Range(max); },这样你的循环就变成了 for (int i : range(5)) {} - Henry Keiter
@HenryKeiter 这是一个不错的建议,我非常喜欢它,我会更新我的答案(并给你功劳)。 - jlordo
这是一个不错的回答,但并不是针对问题的。它只是暗示着“不,没有像range这样的函数,你必须实现自己的迭代器”。很抱歉,给你打-1分。 - OndroMih

15

嗯...for (int i = 0; i < k; i++)?你不必整天写增强型的for循环,虽然它们很酷...

为了论证而已:

for (int i : range(k)) 字符数:22

for (int i = 0; i < k; i++) 字符数:27

不考虑实现的range,两者几乎一样。


这是正常的做法,但如果你能为循环创建一个数组,那将会更简单。 - Kacper Lubisz
1
不过,这并不是他想问的;他想知道是否有一种“更简单”的方法。 - Henry Keiter
1
@HenryKeiter:没错,只是想反驳楼主的观点:“用Java做这件事会让循环变得更容易。” - zw324
1
嗯,我肯定不能反驳你。看起来为了节省几个字符(并忽略所有惯例),需要付出很多努力,但我不在这里评判人们可能想使用的(反)习语 :) - Henry Keiter
@ExotickBoyPl,如果你看一下我的回答,你可以做出类似于数组的东西,但效率更高。 - jlordo
只是为了明确起见,range()不是Java函数,以防像我这样的白痴想尝试它。 :P - user124384

11

使用Apache Commons Lang

new IntRange(0, 3).toArray();

我通常不会建议为了这么简单的事情引入外部库,但是Apache Commons已经被广泛使用,你可能已经在你的项目中使用了它!

编辑:我知道这不一定像for循环那样简单或快速,但这是一种使意图清晰的语法糖。

编辑:参见@zengr的答案,使用Java 8中的IntStream


虽然它不是我期望的那样,但知道这点仍然很好。 - Kacper Lubisz
3
这也会比传统的for循环慢得多。 - Louis Wasserman
这个解决方案相当低效 - 对于大范围需要一个大数组。扩展AbstractList是我能想到的最简单有效的解决方案。 - OndroMih

2

如果你真的非常想在Java中获得相同的结果,你需要做更多的工作:

public int[] range(int start, int end, int step) {
    int n = (int) Math.ceil((end-start)/(double)step);
    int[] arange = new int[n];
    for (int i = 0; i < n; i++)
        arange[i] = i*step+start;
    return arange;
}

现在 range(0, 4, 1) 将会返回期望的值,就像 Python 一样: [0, 1, 2, 3]。可惜在 Java 中没有更简单的方法,它不像 Python 那样具有表达力。

实现有一些缺陷。运行int[] range = range(5, 33, 5); System.out.println(Arrays.toString(range)); - jlordo

2

这并不是真的可用。但你可以创建一个静态方法并使用它 -

public static int[] range(int index){
    int[] arr = new int[index];
    for(int i=0;i<index;i++){
        arr[i]=i;
    }
    return arr;
}

如果你想要一个范围到Integer.MAX_VALUE的话,那将会创建一个巨大的数组 ;) - jlordo
你可以检查一下你可用的主内存,甚至可以再添加一些呢,嘿嘿 :P - Subhrajyoti Majumder

0

Java中没有与range函数相对应的函数,但有一个增强型for循环

for (String s : strings) {
    // Do stuff
}

如果你真的很喜欢这种语法,你也可以自己编写range函数,但这似乎有点傻。

public static int[] range(int length) {
    int[] r = new int[length];
    for (int i = 0; i < length; i++) {
        r[i] = i;
    }
    return r;
}

// ...

String s;
for (int i : range(arrayOfStrings.length)) {
    s = arrayOfStrings[i];
    // Do stuff
}

如果你想要一个范围到Integer.MAX_VALUE的话,那将会创建一个巨大的数组 ;) - jlordo
@jlordo 嗯,那肯定是真的;-) 但在Python(2)中,“range”函数也是如此,我觉得写一个迭代器只是为了避免编写基本循环有些过度设计(尽管你的答案实际上做到了,哈哈)。 - Henry Keiter
对于一个简单的循环来说,这肯定是过度设计了。虽然你可以修改迭代器以使用 Python 的 range() 方法中的所有其他选项,并且使用更少的内存;)感谢 +1。 - jlordo

0
据我所知,Java中没有相应的函数。但是你可以自己编写它:
public static int[] range(int n) {
    int[] ans = new int[n];
    int i;
    for(i = 0; i < n; i++) {
        ans[i] = i;
    }
    return ans;
}

如果你想要一个范围到Integer.MAX_VALUE的话,那将会创建一个巨大的数组 ;) - jlordo
@jlordo 如果你这样推送它,是的,它会...而Python的range()函数也会这样。 - Barranka
1
这就是为什么我喜欢Java,因为它很容易实现功能而不需要使用太多的内存 :) - jlordo

0

你可以用以下代码在Java中替换Python中的range。注意:我不是根据你的代码,我只是写了一小段代码并向你展示。

在Python中,你会这样做...

if -2 <= x <= 10:
     print(x) 

在Java中,您可以替换此范围并执行...

if(x >= -2 && x <= 10){
System.out.println("x")
}

通过在Java中执行上述代码,您不需要范围,但是您有-2 <= x <= 10范围,并将其拆分为x> = -2和x <= 10。这意味着相同的事情,但是我在Java中解释的可能需要编译器更长的时间来阅读。因此,如果您正在使用Python,请使用前者的代码格式,如果您正在使用Java,请使用后者的代码格式。

欢迎来到Stackoverflow并祝贺您发表了第一篇答案。在这里,我们努力保持回答集中于所要求的具体问题。目前不清楚您所写的内容与Java中是否有类似range(,,)的等效功能有何关联。您可能希望通过更直接地将其与特定问题相关联来加强您的答案。 - piterbarg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接