All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.helpers.collection.Iterables Maven / Gradle / Ivy

Go to download

Neo4j kernel is a lightweight, embedded Java database designed to store data structured as graphs rather than tables. For more information, see http://neo4j.org.

There is a newer version: 5.26.0
Show newest version
/*
 * Copyright (c) 2002-2015 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.helpers.collection;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

import org.neo4j.graphdb.ResourceIterable;
import org.neo4j.graphdb.ResourceIterator;
import org.neo4j.function.Function;
import org.neo4j.helpers.Predicate;

import static java.util.Arrays.asList;

import static org.neo4j.helpers.collection.IteratorUtil.asResourceIterator;

/**
 * TODO: Combine this and {@link IteratorUtil} into one class
 */
public final class Iterables
{
    private static Iterable EMPTY = new Iterable()
    {
        Iterator iterator = new Iterator()
        {
            @Override
            public boolean hasNext()
            {
                return false;
            }

            @Override
            public Object next()
            {
                throw new NoSuchElementException();
            }

            @Override
            public void remove()
            {
            }
        };

        @Override
        public Iterator iterator()
        {
            return iterator;
        }
    };

    @SuppressWarnings("unchecked")
    public static  Iterable empty()
    {
        return EMPTY;
    }


    public static  Iterable limit( final int limitItems, final Iterable iterable )
    {
        return new Iterable()
        {
            @Override
            public Iterator iterator()
            {
                final Iterator iterator = iterable.iterator();

                return new Iterator()
                {
                    int count;

                    @Override
                    public boolean hasNext()
                    {
                        return count < limitItems && iterator.hasNext();
                    }

                    @Override
                    public T next()
                    {
                        count++;
                        return iterator.next();
                    }

                    @Override
                    public void remove()
                    {
                        iterator.remove();
                    }
                };
            }
        };
    }

    public static  Function, Iterable> limit( final int limitItems )
    {
        return new Function, Iterable>()
        {
            @Override
            public Iterable apply( Iterable ts )
            {
                return limit( limitItems, ts );
            }
        };
    }

    public static  Iterable unique( final Iterable iterable )
    {
        return new Iterable()
        {
            @Override
            public Iterator iterator()
            {
                final Iterator iterator = iterable.iterator();

                return new Iterator()
                {
                    Set items = new HashSet<>();
                    T nextItem;

                    @Override
                    public boolean hasNext()
                    {
                        while ( iterator.hasNext() )
                        {
                            nextItem = iterator.next();
                            if ( items.add( nextItem ) )
                            {
                                return true;
                            }
                        }

                        return false;
                    }

                    @Override
                    public T next()
                    {
                        if ( nextItem == null && !hasNext() )
                        {
                            throw new NoSuchElementException();
                        }

                        return nextItem;
                    }

                    @Override
                    public void remove()
                    {
                    }
                };
            }
        };
    }

    public static > C addAll( C collection, Iterable iterable )
    {
        Iterator iterator = iterable.iterator();
        try
        {
            while (iterator.hasNext())
            {
                collection.add( iterator.next() );
            }
        }
        finally
        {
            if (iterator instanceof AutoCloseable)
            {
                try
                {
                    ((AutoCloseable)iterator).close();
                }
                catch ( Exception e )
                {
                    // Ignore
                }
            }
        }

        return collection;
    }

    public static long count( Iterable iterable )
    {
        long c = 0;
        for ( Iterator iterator = iterable.iterator(); iterator.hasNext(); iterator.next() )
        {
            c++;
        }
        return c;
    }

    public static  Iterable filter( Predicate specification, Iterable i )
    {
        return new FilterIterable<>( i, specification );
    }

    public static  Iterator filter( Predicate specification, Iterator i )
    {
        return new FilterIterable.FilterIterator<>( i, specification );
    }

    public static  X first( Iterable i )
    {
        Iterator iter = i.iterator();
        if ( iter.hasNext() )
        {
            return iter.next();
        }
        else
        {
            return null;
        }
    }

    public static  X single( Iterable i )
    {
        return IteratorUtil.single( i );
    }

    public static  Iterable skip( final int skip, final Iterable iterable )
    {
        return new Iterable()
        {
            @Override
            public Iterator iterator()
            {
                Iterator iterator = iterable.iterator();

                for ( int i = 0; i < skip; i++ )
                {
                    if ( iterator.hasNext() )
                    {
                        iterator.next();
                    }
                    else
                    {
                        return Iterables.empty().iterator();
                    }
                }

                return iterator;
            }
        };
    }

    public static  X last( Iterable i )
    {
        Iterator iter = i.iterator();
        X item = null;
        while ( iter.hasNext() )
        {
            item = iter.next();
        }

        return item;
    }

    public static  Iterable reverse( Iterable iterable )
    {
        List list = toList( iterable );
        Collections.reverse( list );
        return list;
    }

    @SafeVarargs
    public static > Iterable flatten( I... multiIterator )
    {
        return new FlattenIterable<>( asList(multiIterator) );
    }

    @SafeVarargs
    public static  Iterable mix( final Iterable... iterables )
    {
        return new Iterable()
        {
            @Override
            public Iterator iterator()
            {
                final Iterable> iterators = toList( map( new Function, Iterator>()
                {
                    @Override
                    public Iterator apply( Iterable iterable )
                    {
                        return iterable.iterator();
                    }
                }, asList(iterables) ) );

                return new Iterator()
                {
                    Iterator> iterator;

                    Iterator iter;

                    @Override
                    public boolean hasNext()
                    {
                        for ( Iterator iterator : iterators )
                        {
                            if ( iterator.hasNext() )
                            {
                                return true;
                            }
                        }

                        return false;
                    }

                    @Override
                    public T next()
                    {
                        if ( iterator == null )
                        {
                            iterator = iterators.iterator();
                        }

                        while ( iterator.hasNext() )
                        {
                            iter = iterator.next();

                            if ( iter.hasNext() )
                            {
                                return iter.next();
                            }
                        }

                        iterator = null;

                        return next();
                    }

                    @Override
                    public void remove()
                    {
                        if ( iter != null )
                        {
                            iter.remove();
                        }
                    }
                };
            }
        };
    }

    public static  Iterable map( Function function, Iterable from )
    {
        return new MapIterable<>( from, function );
    }

    public static  Iterator map( Function function, Iterator from )
    {
        return new MapIterable.MapIterator<>( from, function );
    }

    public static  Iterator flatMap( Function> function, Iterator from )
    {
        return new CombiningIterator<>( map(function, from) );
    }

    @SafeVarargs
    @SuppressWarnings("unchecked")
    public static  Iterable iterable( C... items )
    {
        return (Iterable) asList(items);
    }

    @SuppressWarnings("unchecked")
    public static  Iterable cast( Iterable iterable )
    {
        return (Iterable) iterable;
    }

    @SafeVarargs
    @SuppressWarnings("unchecked")
    public static  Iterable concat( Iterable... iterables )
    {
        return concat( asList( (Iterable[]) iterables ) );
    }

    public static  Iterable concat( final Iterable> iterables )
    {
        return new CombiningIterable<>( iterables );
    }

    @SafeVarargs
    @SuppressWarnings("unchecked")
    public static  Iterator concat( Iterator... iterables )
    {
        return concat( Arrays.asList( (Iterator[]) iterables ).iterator() );
    }

    public static  ResourceIterator concatResourceIterators( Iterator> iterators )
    {
        return new CombiningResourceIterator<>(iterators);
    }

    public static  Iterator concat( Iterator> iterators )
    {
        return new CombiningIterator<>(iterators);
    }

    public static  Function cast()
    {
        return new Function()
        {
            @Override
            @SuppressWarnings("unchecked")
            public TO apply( FROM from )
            {
                return (TO) from;
            }
        };
    }

    public static  Iterable prepend( final C item, final Iterable iterable )
    {
        return new Iterable()
        {
            @Override
            public Iterator iterator()
            {
                return new Iterator()
                {
                    T first = item;
                    Iterator iterator;

                    @Override
                    public boolean hasNext()
                    {
                        if ( first != null )
                        {
                            return true;
                        }
                        else
                        {
                            if ( iterator == null )
                            {
                                iterator = iterable.iterator();
                            }
                        }

                        return iterator.hasNext();
                    }

                    @Override
                    public T next()
                    {
                        if ( first != null )
                        {
                            try
                            {
                                return first;
                            }
                            finally
                            {
                                first = null;
                            }
                        }
                        else
                        {
                            return iterator.next();
                        }
                    }

                    @Override
                    public void remove()
                    {
                    }
                };
            }
        };
    }

    public static  Iterable append( final C item, final Iterable iterable )
    {
        return new Iterable()
        {
            @Override
            public Iterator iterator()
            {
                final Iterator iterator = iterable.iterator();

                return new Iterator()
                {
                    T last = item;

                    @Override
                    public boolean hasNext()
                    {
                        return iterator.hasNext() || last != null;
                    }

                    @Override
                    public T next()
                    {
                        if ( iterator.hasNext() )
                        {
                            return iterator.next();
                        }
                        else
                        {
                            try
                            {
                                return last;
                            }
                            finally
                            {
                                last = null;
                            }
                        }
                    }

                    @Override
                    public void remove()
                    {
                    }
                };
            }
        };
    }

    public static  Iterable cache( Iterable iterable )
    {
        return new CacheIterable<>( iterable );
    }

    public static  List toList( Iterable iterable )
    {
        return addAll( new ArrayList(), iterable );
    }

    public static  List toList( Iterator iterator)
    {
        List list = new ArrayList<>(  );
        while ( iterator.hasNext() )
        {
            list.add(iterator.next());
        }
        return list;
    }

    public static Object[] toArray( Iterable iterable )
    {
        return toArray( Object.class, iterable );
    }

    @SuppressWarnings("unchecked")
    public static  T[] toArray( Class componentType, Iterable iterable )
    {
        if ( iterable == null )
        {
            return null;
        }

        List list = toList( iterable );
        return list.toArray( (T[]) Array.newInstance( componentType, list.size() ) );
    }

    public static  ResourceIterable asResourceIterable( final Iterable labels )
    {
        return new ResourceIterable()
        {
            @Override
            public ResourceIterator iterator()
            {
                return asResourceIterator( labels.iterator() );
            }
        };
    }

    public static  ResourceIterable asResourceIterable( final ResourceIterator it )
    {
        return new ResourceIterable()
        {
            @Override
            public ResourceIterator iterator()
            {
                return it;
            }
        };
    }

    public static  Set toSet( Iterable iterable )
    {
        return addAll( new HashSet(), iterable );
    }

    public static String toString( Iterable values, String separator )
    {
        Iterator it = values.iterator();
        StringBuilder sb = new StringBuilder();
        while(it.hasNext())
        {
            sb.append( it.next().toString() );
            if(it.hasNext())
            {
                sb.append( separator );
            }
        }
        return sb.toString();
    }

    private static class MapIterable
            implements Iterable
    {
        private final Iterable from;
        private final Function function;

        public MapIterable( Iterable from, Function function )
        {
            this.from = from;
            this.function = function;
        }

        @Override
        public Iterator iterator()
        {
            return new MapIterator<>( from.iterator(), function );
        }

        static class MapIterator
                implements Iterator
        {
            private final Iterator fromIterator;
            private final Function function;

            public MapIterator( Iterator fromIterator, Function function )
            {
                this.fromIterator = fromIterator;
                this.function = function;
            }

            @Override
            public boolean hasNext()
            {
                return fromIterator.hasNext();
            }

            @Override
            public TO next()
            {
                FROM from = fromIterator.next();

                return function.apply( from );
            }

            @Override
            public void remove()
            {
                fromIterator.remove();
            }
        }
    }

    private static class FilterIterable
            implements Iterable
    {
        private final Iterable iterable;

        private final Predicate specification;

        public FilterIterable( Iterable iterable, Predicate specification )
        {
            this.iterable = iterable;
            this.specification = specification;
        }

        @Override
        public Iterator iterator()
        {
            return new FilterIterator<>( iterable.iterator(), specification );
        }

        static class FilterIterator
                implements Iterator
        {
            private final Iterator iterator;

            private final Predicate specification;

            private T currentValue;
            boolean finished = false;
            boolean nextConsumed = true;

            public FilterIterator( Iterator iterator, Predicate specification )
            {
                this.specification = specification;
                this.iterator = iterator;
            }

            public boolean moveToNextValid()
            {
                boolean found = false;
                while ( !found && iterator.hasNext() )
                {
                    T currentValue = iterator.next();
                    boolean satisfies = specification.accept( currentValue );

                    if ( satisfies )
                    {
                        found = true;
                        this.currentValue = currentValue;
                        nextConsumed = false;
                    }
                }
                if ( !found )
                {
                    finished = true;
                }
                return found;
            }

            @Override
            public T next()
            {
                if ( !nextConsumed )
                {
                    nextConsumed = true;
                    return currentValue;
                }
                else
                {
                    if ( !finished )
                    {
                        if ( moveToNextValid() )
                        {
                            nextConsumed = true;
                            return currentValue;
                        }
                    }
                }
                throw new NoSuchElementException( "This iterator is exhausted." );
            }

            @Override
            public boolean hasNext()
            {
                return !finished && (!nextConsumed || moveToNextValid());
            }

            @Override
            public void remove()
            {
            }
        }
    }

    private static class FlattenIterable>
            implements Iterable
    {
        private final Iterable iterable;

        public FlattenIterable( Iterable iterable )
        {
            this.iterable = iterable;
        }

        @Override
        public Iterator iterator()
        {
            return new FlattenIterator<>( iterable.iterator() );
        }

        static class FlattenIterator>
                implements Iterator
        {
            private final Iterator iterator;
            private Iterator currentIterator;

            public FlattenIterator( Iterator iterator )
            {
                this.iterator = iterator;
                currentIterator = null;
            }

            @Override
            public boolean hasNext()
            {
                if ( currentIterator == null )
                {
                    if ( iterator.hasNext() )
                    {
                        I next = iterator.next();
                        currentIterator = next.iterator();
                    }
                    else
                    {
                        return false;
                    }
                }

                while ( !currentIterator.hasNext() &&
                        iterator.hasNext() )
                {
                    currentIterator = iterator.next().iterator();
                }

                return currentIterator.hasNext();
            }

            @Override
            public T next()
            {
                return currentIterator.next();
            }

            @Override
            public void remove()
            {
                if ( currentIterator == null )
                {
                    throw new IllegalStateException();
                }

                currentIterator.remove();
            }
        }
    }

    private static class CacheIterable
            implements Iterable
    {
        private final Iterable iterable;
        private Iterable cache;

        private CacheIterable( Iterable iterable )
        {
            this.iterable = iterable;
        }

        @Override
        public Iterator iterator()
        {
            if ( cache != null )
            {
                return cache.iterator();
            }

            final Iterator source = iterable.iterator();

            return new Iterator()
            {
                List iteratorCache = new ArrayList<>();

                @Override
                public boolean hasNext()
                {
                    boolean hasNext = source.hasNext();
                    if ( !hasNext )
                    {
                        cache = iteratorCache;
                    }
                    return hasNext;
                }

                @Override
                public T next()
                {
                    T next = source.next();
                    iteratorCache.add( next );
                    return next;
                }

                @Override
                public void remove()
                {

                }
            };
        }
    }

    /**
     * Returns the index of the first occurrence of the specified element
     * in this iterable, or -1 if this iterable does not contain the element.
     * More formally, returns the lowest index i such that
     * (o==null ? get(i)==null : o.equals(get(i))),
     * or -1 if there is no such index.
     */
    public static  int indexOf( T itemToFind, Iterable iterable )
    {
        if ( itemToFind == null )
        {
            int index = 0;
            for ( T item : iterable )
            {
                if ( item == null )
                {
                    return index;
                }
                index++;
            }
        }
        else
        {
            int index = 0;
            for ( T item : iterable )
            {
                if ( itemToFind.equals( item ) )
                {
                    return index;
                }
                index++;
            }
        }
        return -1;
    }

    public static  Iterable option( final T item )
    {
        if ( item == null )
        {
            return Collections.emptyList();
        }

        return new Iterable()
        {
            @Override
            public Iterator iterator()
            {
                return IteratorUtil.iterator( item );
            }
        };
    }

    @SuppressWarnings( "rawtypes" )
    public static  Iterable sort( Iterable iterable, final Function compareFunction )
    {
        List list = toList( iterable );
        Collections.sort( list, new Comparator()
        {
            @SuppressWarnings( "unchecked" )
            @Override
            public int compare( T o1, T o2 )
            {
                return compareFunction.apply( o1 ).compareTo( compareFunction.apply( o2 ) );
            }
        } );
        return list;
    }

    public static String join( String joinString, Iterable iter )
    {
        return join( joinString, iter.iterator() );
    }

    public static String join( String joinString, Iterator iter )
    {
        StringBuilder sb = new StringBuilder();
        while(iter.hasNext())
        {
            sb.append( iter.next().toString() );
            if(iter.hasNext())
            {
                sb.append( joinString );
            }
        }
        return sb.toString();
    }
}