java Guava 迭代器,并在列表对象中迭代列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14340481/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 15:56:22  来源:igfitidea点击:

Guava iterators, and iterating over a list within a list object

javaiteratorguava

提问by GobiasKoffi

I have the following example code which consists of 3-nested for-loops.

我有以下示例代码,其中包含 3 个嵌套的 for 循环。

for(Continent continent : continentList) 
{
    for(Country country : continent.getCountries())
    {
        for(City city : country.getCities())
        {
            //Do stuff with city objects
        }
    }
}

Is there any way to mimic this nested for-loop using Guava and iterators? I've been trying to find a suitable example without much luck, and I was wondering if someone could help me out? A coworker of mine mentioned using filters.

有没有办法使用 Guava 和迭代器来模拟这个嵌套的 for 循环?我一直试图找到一个合适的例子,但运气不佳,我想知道是否有人可以帮助我?我的一位同事提到使用过滤器。

EDIT: Fixed tiny bug in example code

编辑:修复了示例代码中的小错误

回答by ig0774

As Peter Lawrey commented, this is almost certainly going to be simpler as nested loops. More over, the Guava documentationgives this warning:

正如 Peter Lawrey 评论的那样,这几乎肯定会比嵌套循环更简单。更重要的是,番石榴文档给出了这个警告:

Imperative code should be your default, your first choice as of Java 7. You should not use functional idioms unless you are absolutely sure of one of the following:

  • Use of functional idioms will result in net savings of lines of code for your entire project. Moving the definition of a function to another file, or a constant, does not help.
  • For efficiency, you need a lazily computed view of the transformed collection and cannot settle for an explicitly computed collection. Additionally, you have read and reread Effective Java, item 55, and besides following those instructions, you have actually done benchmarking to prove that this version is faster, and can cite numbers to prove it.

Please be sure, when using Guava's functional utilities, that the traditional imperative way of doing things isn't more readable. Try writing it out. Was that so bad? Was that more readable than the preposterously awkward functional approach you were about to try?

命令式代码应该是您的默认代码,也是您从 Java 7 开始的首选。除非您绝对确定以下其中一项,否则不应使用函数式惯用语:

  • 使用功能性习语将导致整个项目的代码行净节省。将函数的定义移到另一个文件或常量中并没有帮助。
  • 为了提高效率,您需要对转换后的集合进行延迟计算的视图,而不能满足于显式计算的集合。此外,您已经阅读并重读了 Effective Java,第 55 项,除了遵循这些说明之外,您实际上还进行了基准测试以证明该版本更快,并且可以引用数字来证明这一点。

请确保,在使用 Guava 的函数式实用程序时,传统的命令式做事方式并不更具可读性。试着写出来。有那么糟糕吗?这是否比您即将尝试的荒谬笨拙的函数式方法更具可读性?

However, if you're insistent on ignoring advice, you could use something like this monstrosity (note I haven't actually tried to compile or run this):

但是,如果你坚持忽略建议,你可以使用类似这样的东西(注意我实际上并没有尝试编译或运行它):

FluentIterable.from(continentList)
    .transform(new Function<Continent, Void>() {
        public Void apply(Continent continent) {
            return FluentIterable.from(continent.getCountries())
                .transform(new Function<Country, Void>() {
                    public Void apply(Country country) {
                        return FluentIterable.from(country.getCities())
                            .transform(new Function<City, Void>() {
                                public Void apply(City city) {
                                    // do stuff with city object
                                    return null;
                                }
                            });
                    }
                });
        }
    });

Now ask yourself: Which would you want to maintain? Which is going to be the most efficient?

现在问问自己:你想维护哪个?哪个将是最有效的?

There are valid use-cases for Guava's functional idiom. Replacing Java for loops, even nested for loops, is not one of them.

Guava 的功能习语有一些有效的用例。替换 Java for 循环,甚至嵌套的 for 循环,都不是其中之一。

回答by RikH

You can define static functions for:
? getCountries() in Continent, Continents or Functions
? getCities() in Country, Countries or Functions

您可以定义静态函数为:
?getCountries() 在 Continent、Continents 或 Functions 中
?国家、国家或函数中的 getCities()

Now you can do something like...

现在你可以做一些像......

FluentIterable.from(continentList)
    .transformAndConcat(Continent.getCountriesFunction())
    .transformAndConcat(Country.getCitiesFunction())
    . //filter //tranform //find //toList() //etc.

If:
? You use Guava like this (more) often.
? And have certain rules/thoughts over where you define your Functions and Predicates.
? And have varying (complex) things to filter or search for.
Then it can be a great boon and can make many situations quite a bit easier. I know I'm glad I did.

If you use it sparsely, then I'll have to agree with @Louis Wasserman. Then it's not worth the hassle. Also, defining Functions and Predicates as an anonymous inner class like the other examples... is really ugly.

如果:
? 你经常像这样(更多)使用番石榴。
? 并且对定义函数和谓词的位置有一定的规则/想法。
? 并且有不同(复杂)的东西要过滤或搜索。
然后它可以是一个巨大的福音,可以使许多情况变得更容易。我知道我很高兴我做到了。

如果您很少使用它,那么我将不得不同意@Louis Wasserman。那么它是不值得的麻烦。此外,像其他示例一样将函数和谓词定义为匿名内部类......真的很难看。

回答by Olivier Grégtheitroade

Another monstrosity, using AbstractIterator:

另一个怪物,使用 AbstractIterator:

    class CityIterable implements Iterable<City> {
        List<Continent> continents;

        CityIterable(List<Continent> continents) {
            this.continents = continents;
        }

        @Override
        public Iterator<City> iterator() {
            return new AbstractIterator<City>() {
                Iterator<Continent> continentIterator = continents.iterator();
                Iterator<Country> countryIterator;
                Iterator<City> cityIterator;

                @Override
                protected City computeNext() {
                    if (cityIterator != null && cityIterator.hasNext()) {
                        return cityIterator.next();
                    }
                    if (countryIterator != null && countryIterator.hasNext()) {
                        cityIterator = countryIterator.next().getCities().iterator();
                        return computeNext();
                    }
                    if (continentIterator.hasNext()) {
                        countryIterator = continentIterator.next().getCountries().iterator();
                        return computeNext();
                    }
                    return endOfData();
                }
            };
        }
    }

Then calling it:

然后调用它:

    for (City city: new CityIterable(continentList)) {
        System.out.println(city.name);
    }

Given how this monstruosity, follow ig0774's advice and keep the nested loops.

鉴于这种怪异行为,请遵循 ig0774 的建议并保留嵌套循环

P.S. No need for filters.

PS 不需要过滤器。

回答by artbristol

No, there isn't an easy way. Also, it would be more verbose than the for-each loop in your question.

不,没有简单的方法。此外,它会比您问题中的 for-each 循环更冗长。

See http://code.google.com/p/guava-libraries/issues/detail?id=218#c5and the caveats in http://code.google.com/p/guava-libraries/wiki/FunctionalExplained

http://code.google.com/p/guava-libraries/issues/detail?id=218#c5并在告诫http://code.google.com/p/guava-libraries/wiki/FunctionalExplained

回答by Sean Patrick Floyd

I agree with the others in that the nested loops are the most efficient way to go. However: I'd extract each loop level to a separate method to both maintain readability and make sure that each method does exactly one thing:

我同意其他人的看法,因为嵌套循环是最有效的方法。但是:我会将每个循环级别提取到一个单独的方法中,以保持可读性并确保每个方法只做一件事:

public void doStuffWithWorld(World world){
    for (Continent continent : world.getContinents()) {
        doStuffWithContinent(continent);
    }
}

private void doStuffWithContinent(Continent continent) {
    for (Country country : continent.getCountries()) {
        doStuffWithCountry(country);
    }
}

private void doStuffWithCountry(Country country) {
    for(City city : country.getCities()){
        doStuffWithCity(city);
    }
}

private void doStuffWithCity(City city) {
    // do stuff here
}

And if you need to carry some state through the different levels, you have several options: put them in member fields of the containing class, pass a second parameter to all the methods which can either be a map or a custom object.

如果您需要通过不同的级别携带某些状态,您有多种选择:将它们放在包含类的成员字段中,将第二个参数传递给所有方法,这些方法可以是地图或自定义对象。