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

cdc.graphs.core.GraphPath Maven / Gradle / Ivy

package cdc.graphs.core;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * A Path is an ordered list of items (typically nodes or edges).
 *
 * @author Damien Carbonne
 *
 * @param  The item class.
 */
public final class GraphPath {
    private final List items;
    private static final Comparator> DESCENDING_SIZE_COMPARATOR =
            (p1,
             p2) -> p2.size() - p1.size();

    private GraphPath() {
        this.items = Collections.emptyList();
    }

    private GraphPath(List items) {
        this.items = Collections.unmodifiableList(new ArrayList<>(items));
    }

    /**
     * @return The list of items of this path.
     */
    public List getItems() {
        return items;
    }

    /**
     * @return The number of items in the path.
     */
    public int size() {
        return items.size();
    }

    /**
     * @return True if this path is empty.
     */
    public boolean isEmpty() {
        return items.isEmpty();
    }

    /**
     * Returns true when an item is contained in this path.
     *
     * @param item The item.
     * @return True when this path contains item.
     */
    public boolean contains(T item) {
        return items.contains(item);
    }

    /**
     * @return The parent path.
     */
    public GraphPath parent() {
        if (size() <= 1) {
            return new GraphPath<>();
        } else {
            return new GraphPath<>(items.subList(0, items.size() - 1));
        }
    }

    /**
     * Returns true when this path contains another path.
     *
     * @param other The other path.
     * @return True when other is a sub-path of this path.
     */
    public boolean includes(GraphPath other) {
        if (other.size() > size()) {
            return false;
        } else {
            final int delta = size() - other.size();
            for (int d = 0; d <= delta; d++) {
                boolean match = true;
                for (int index = 0; index < other.size(); index++) {
                    if (items.get(index + d) != other.items.get(index)) {
                        match = false;
                        break;
                    }
                }
                if (match) {
                    return true;
                }
            }
            return false;
        }
    }

    /**
     * @param other The other path.
     * @return {@code true} if this path and {@code other} path have common items.
     */
    public boolean hasCommonItemsWith(GraphPath other) {
        if (items.size() <= other.items.size()) {
            final Set set = new HashSet<>(other.items);
            for (final T item : items) {
                if (set.contains(item)) {
                    return true;
                }
            }
            return false;
        } else {
            final Set set = new HashSet<>(items);
            for (final T item : other.items) {
                if (set.contains(item)) {
                    return true;
                }
            }
            return false;
        }
    }

    /**
     * Reduces a set of paths so that no path in the set is a sub-path of another path.
     *
     * @param  The item class.
     * @param paths The set of paths.
     */
    public static  void reduce(Set> paths) {
        // When there are too few paths, nothing needs t be done
        if (paths.size() <= 1) {
            return;
        }

        // There are at least 2 paths

        // Add paths to tmp in descending size
        final List> tmp = new ArrayList<>(paths);
        Collections.sort(tmp, DESCENDING_SIZE_COMPARATOR);

        // Resets paths set
        // It will be filled with appropriate paths
        paths.clear();

        // Test paths from longer ones to smaller ones
        for (int index = 0; index < tmp.size(); index++) {
            // Next path to test
            final GraphPath next = tmp.get(index);
            // Check whether next is included in one of the paths contained in
            // paths or not.
            boolean included = false;
            for (final GraphPath path : paths) {
                if (path.includes(next)) {
                    included = true;
                    break;
                }
            }
            if (!included) {
                paths.add(next);
            }
        }
    }

    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof GraphPath)) {
            return false;
        }
        final GraphPath o = (GraphPath) other;
        return items.equals(o.items);
    }

    @Override
    public int hashCode() {
        return items.hashCode();
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder();
        builder.append("[");
        boolean first = true;
        for (final T item : items) {
            if (!first) {
                builder.append(" ");
            }
            builder.append(item);
            first = false;
        }
        builder.append("]");
        return builder.toString();
    }

    public static  Builder builder() {
        return new Builder<>();
    }

    public static  Builder builder(final Class cls) {
        return new Builder<>();
    }

    public static final class Builder {
        private final List items = new ArrayList<>();

        private Builder() {
        }

        /**
         * Clears this path builder.
         *
         * @return This Builder.
         */
        public Builder clear() {
            items.clear();
            return this;
        }

        /**
         * Adds an item at the end of path.
         *
         * @param item the item.
         * @return This Builder.
         */
        public Builder push(T item) {
            items.add(item);
            return this;
        }

        /**
         * Adds items at the end of path.
         *
         * @param items The items.
         * @return This Builder.
         */
        @SuppressWarnings("unchecked")
        public Builder push(T... items) {
            Collections.addAll(this.items, items);
            return this;
        }

        public Builder push(List items) {
            this.items.addAll(items);
            return this;
        }

        public Builder push(GraphPath path) {
            items.addAll(path.getItems());
            return this;
        }

        /**
         * Removes the last item of the path.
         *
         * @return This Builder.
         */
        public Builder pop() {
            items.remove(items.size() - 1);
            return this;
        }

        public List getItems() {
            return items;
        }

        public boolean contains(T item) {
            return items.contains(item);
        }

        public GraphPath build() {
            return new GraphPath<>(items);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy