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

net.sf.mpxj.common.HierarchyHelper Maven / Gradle / Ivy

Go to download

Library that provides facilities to allow project information to be manipulated in Java and .Net. Supports a range of data formats: Microsoft Project Exchange (MPX), Microsoft Project (MPP,MPT), Microsoft Project Data Interchange (MSPDI XML), Microsoft Project Database (MPD), Planner (XML), Primavera (PM XML, XER, and database), Asta Powerproject (PP, MDB), Asta Easyplan (PP), Phoenix Project Manager (PPX), FastTrack Schedule (FTS), and the Standard Data Exchange Format (SDEF).

There is a newer version: 13.6.0
Show newest version
/*
 * file:       HierarchyHelper.java
 * author:     Jon Iles
 * date:       2023-11-14
 */

/*
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library 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 Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */

package net.sf.mpxj.common;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * Helper methods for working with hierarchical data.
 */
public class HierarchyHelper
{
   /**
    * Given a list of items, sort the items such that parent items always appear
    * before child items. This allows for "one shot" creation of object instances
    * based on this data rather than having to make a second pass to create
    * the hierarchy.
    *
    * @param  ID type
    * @param  value type
    * @param list list of items
    * @param getId function to retrieve an item's ID
    * @param getParentId function to retrieve an item's parent ID
    * @return list sorted to ensure parents appear before children
    */
   public static final  List sortHierarchy(List list, Function getId, Function getParentId)
   {
      return sortHierarchy(list, getId, getParentId, null);
   }

   /**
    * Given a list of items, sort the items such that parent items always appear
    * before child items and ensure child items are sorted.
    * This allows for "one shot" creation of object instances
    * based on this data rather than having to make a second pass to create
    * the hierarchy.
    *
    * @param  ID type
    * @param  value type
    * @param list list of items
    * @param getId function to retrieve an item's ID
    * @param getParentId function to retrieve an item's parent ID
    * @param comparator sort order for items within the hierarchy
    * @return list sorted to ensure parents appear before children
    */
   public static final  List sortHierarchy(List list, Function getId, Function getParentId, Comparator comparator)
   {
      // Bail out early if sorting is not required
      if (list.size() < 2 || list.stream().allMatch(v -> getParentId.apply(v) == null))
      {
         return list;
      }

      Map> nodes = new HashMap<>();
      list.forEach(i -> nodes.put(getId.apply(i), new HierarchyNode<>(i)));

      HierarchyNode root = new HierarchyNode<>();
      for (Map.Entry> entry : nodes.entrySet())
      {
         HierarchyNode parent = nodes.get(getParentId.apply(entry.getValue().getItem()));
         (parent == null ? root : parent).addChild(entry.getValue());
      }

      return comparator == null ? addChildNodes(new ArrayList<>(), root) : addChildNodes(new ArrayList<>(), root, (o1, o2) -> comparator.compare(o1.getItem(), o2.getItem()));
   }

   /**
    * Recursively add parent and child items to a list.
    *
    * @param  value type
    * @param list list to which items are added
    * @param parent parent node
    * @return list with nodes added
    */
   private static  List addChildNodes(List list, HierarchyNode parent)
   {
      parent.getChildNodes().forEach(c -> {
         list.add(c.getItem());
         addChildNodes(list, c);
      });
      return list;
   }

   /**
    * Recursively add parent and child items to a list, with child items sorted.
    *
    * @param  value type
    * @param list list to which items are added
    * @param parent parent node
    * @param hierarchyNodeComparator sort order for items
    * @return list with nodes added
    */
   private static  List addChildNodes(List list, HierarchyNode parent, Comparator> hierarchyNodeComparator)
   {
      parent.getChildNodes().stream().sorted(hierarchyNodeComparator).forEach(c -> {
         list.add(c.getItem());
         addChildNodes(list, c, hierarchyNodeComparator);
      });
      return list;
   }

   /**
    * Class used to represent an item and any child items.
    *
    * @param  value type
    */
   private static class HierarchyNode
   {
      /**
       * Root node constructor.
       */
      public HierarchyNode()
      {
         this(null);
      }

      /**
       * Constructor.
       *
       * @param item item represented by this node
       */
      public HierarchyNode(V item)
      {
         m_item = item;
      }

      /**
       * Retrieve the item represented by this node.
       *
       * @return item
       */
      public V getItem()
      {
         return m_item;
      }

      /**
       * Add a child node.
       *
       * @param child child node
       */
      public void addChild(HierarchyNode child)
      {
         m_childNodes.add(child);
      }

      /**
       * Retrieve the child nodes.
       *
       * @return child nodes
       */
      public List> getChildNodes()
      {
         return m_childNodes;
      }

      private final V m_item;
      private final List> m_childNodes = new ArrayList<>();
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy