Guava迭代器,迭代列表对象中的列表

时间:2013-01-15 15:00:49

标签: java iterator guava

我有以下示例代码,它由3个嵌套的for循环组成。

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

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

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

5 个答案:

答案 0 :(得分:11)

正如Peter Lawrey评论的那样,这几乎肯定会像嵌套循环一样简单。更重要的是,Guava documentation会发出此警告:

  

命令代码应该是您的默认代码,是Java的首选   7.除非您完全确定以下其中一项,否则不应使用功能习语:

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

使用番石榴的功能时请确定   公用事业,传统的必要做事方式不是   更具可读性。试着把它写出来。真是太糟糕了吗?那更多   比你荒谬笨拙的功能方法更可读   即将尝试?

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

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;
                                }
                            });
                    }
                });
        }
    });

现在问问自己:你想保持哪个?哪个会最有效?

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

答案 1 :(得分:8)

您可以定义静态函数:
•Continent,Continents或Functions中的getCountries() •国家,国家或职能中的getCities()

现在你可以做点什么......

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

如果:
•您经常使用番石榴(更多) •对于定义功能和谓词的位置有一定的规则/想法 •有不同(复杂)的东西可以过滤或搜索 然后它可以是一个伟大的福音,可以使许多情况更容易。我知道我很高兴我做到了。

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

答案 2 :(得分:3)

另一个怪物,使用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();
                }
            };
        }
    }

然后调用它:

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

考虑到这种怪异,请遵循ig0774的建议并保留嵌套循环

P.S。无需过滤器。

答案 3 :(得分:2)

不,没有一个简单的方法。而且,它会比你问题中的for-each循环更冗长。

请参阅http://code.google.com/p/guava-libraries/issues/detail?id=218#c5以及http://code.google.com/p/guava-libraries/wiki/FunctionalExplained

中的警告

答案 4 :(得分:1)

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

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
}

如果你需要在不同的级别上携带一些状态,你有几个选择:将它们放在包含类的成员字段中,将第二个参数传递给所有可以是map或自定义对象的方法。