import org. apache. commons. collections4. CollectionUtils;
import org. apache. commons. lang3. mutable. MutableLong;
import org. springframework. lang. NonNull;
import org. springframework. lang. Nullable;
import org. springframework. util. StringUtils; import java . util. * ;
import java . util. function. BiConsumer;
import java . util. function. Function;
import java . util. stream. Collectors;
@SuppressWarnings ( "unused" )
public class TreeUtil { public static < T, I> List< T> buildByParentId ( @NonNull List< T> list, @NonNull Function< T, I> getId, @NonNull Function< T, I> getParentId, @Nullable Comparator< T> comparator, @NonNull BiConsumer< T, List< T>> setSub) { Map< I, T> idNodeMap = list. stream ( ) . collect ( Collectors. toMap ( getId, Function. identity ( ) , ( existing, replacement) -> existing) ) ; Map< I, List< T>> parentIdMap = new HashMap< > ( ) ; for ( T node : list) { I parentId = getParentId. apply ( node) ; parentIdMap. computeIfAbsent ( parentId, k -> new ArrayList< > ( ) ) . add ( node) ; } for ( T node : list) { I id = getId. apply ( node) ; List< T> children = parentIdMap. get ( id) ; if ( children != null) { sortList ( children, comparator) ; setSub. accept ( node, children) ; } } List< T> roots = list. stream ( ) . filter ( node -> { I parentId = getParentId. apply ( node) ; return parentId == null || ! idNodeMap. containsKey ( parentId) ; } ) . collect ( Collectors. toList ( ) ) ; sortList ( roots, comparator) ; return roots; } private static < T> void sortList ( List< T> list, Comparator< T> comparator) { if ( comparator != null && list != null && ! list. isEmpty ( ) ) { list. sort ( comparator) ; } } public static < T, C extends String> List< T> buildByCode ( @NonNull List< T> list, @NonNull Function< T, C> getCode, @Nullable Comparator< T> comparator, @NonNull Function< T, List< T>> getSub, @NonNull BiConsumer< T, List< T>> setSub) { List< T> sortedCodeList = list. stream ( ) . sorted ( Comparator. comparing ( getCode) ) . collect ( Collectors. toList ( ) ) ; Map< C, List< T>> codeGroupMap = new HashMap< > ( ) ; C flagCode = null; for ( T item : sortedCodeList) { C currentCode = getCode. apply ( item) ; if ( flagCode == null || ! currentCode. startsWith ( flagCode) ) { flagCode = currentCode; } codeGroupMap. computeIfAbsent ( flagCode, k -> new ArrayList< > ( ) ) . add ( item) ; } List< T> tree = new ArrayList< > ( ) ; codeGroupMap. forEach ( ( k, v) -> tree. add ( buildNodeByCode ( v, getCode, getSub, setSub) ) ) ; sortTree ( tree, comparator, getSub) ; return tree; } private static < T, C extends String> T buildNodeByCode ( List< T> subList, Function< T, C> getCode, Function< T, List< T>> getSub, BiConsumer< T, List< T>> setSub) { if ( subList. isEmpty ( ) ) { throw new IllegalStateException ( "树构建异常:子节点列表为空" ) ; } Collections. reverse ( subList) ; for ( int i = 0 ; i < subList. size ( ) - 1 ; i++ ) { T child = subList. get ( i) ; T parent = findParentByCode ( child, subList. subList ( i + 1 , subList. size ( ) ) , getCode) ; List< T> children = getSub. apply ( parent) ; if ( children == null) { children = new ArrayList< > ( ) ; setSub. accept ( parent, children) ; } children. add ( child) ; } return subList. get ( subList. size ( ) - 1 ) ; } private static < T, C extends String> T findParentByCode ( T currentNode, List< T> subList, Function< T, C> getCode) { C currentCode = getCode. apply ( currentNode) ; for ( T node : subList) { C parentCode = getCode. apply ( node) ; if ( currentCode. startsWith ( parentCode) && ! currentCode. equals ( parentCode) ) { return node; } } throw new IllegalStateException ( "构建异常:未找到父节点" ) ; } private static < T> void sortTree ( List< T> tree, Comparator< T> comparator, Function< T, List< T>> getSub) { sortList ( tree, comparator) ; for ( T node : tree) { List< T> sub = getSub. apply ( node) ; if ( sub != null && ! sub. isEmpty ( ) ) { sortTree ( sub, comparator, getSub) ; } } } public static < T, R> List< T> getParent ( List< T> list, List< R> ids, Function< ? super T, ? extends R> idExtractor, Function< ? super T, ? extends R> parentIdExtractor, boolean containSelf) { if ( CollectionUtils. isEmpty ( list) || CollectionUtils. isEmpty ( ids) ) { return new ArrayList< > ( ) ; } Map< R, T> idNodeMap = list. stream ( ) . collect ( Collectors. toMap ( idExtractor, Function. identity ( ) ) ) ; Set< R> parentIds = new HashSet< > ( ) ; Deque< R> stack = new LinkedList< > ( ids) ; while ( ! stack. isEmpty ( ) ) { R currentId = stack. pop ( ) ; if ( ! parentIds. contains ( currentId) ) { parentIds. add ( currentId) ; T node = idNodeMap. get ( currentId) ; if ( node != null) { R parentId = parentIdExtractor. apply ( node) ; if ( parentId != null && ! parentIds. contains ( parentId) ) { stack. push ( parentId) ; } } } } return list. stream ( ) . filter ( node -> parentIds. contains ( idExtractor. apply ( node) ) ) . collect ( Collectors. toList ( ) ) ; } public static < T, R> List< T> getChildren ( List< T> list, List< R> ids, Function< ? super T, ? extends R> idExtractor, Function< ? super T, ? extends R> parentIdExtractor, boolean containSelf) { if ( CollectionUtils. isEmpty ( list) || CollectionUtils. isEmpty ( ids) ) { return new ArrayList< > ( ) ; } Map< R, T> idNodeMap = list. stream ( ) . collect ( Collectors. toMap ( idExtractor, Function. identity ( ) , ( existing, replacement) -> existing) ) ; Map< R, List< T>> parentIdMap = list. stream ( ) . collect ( Collectors. groupingBy ( parentIdExtractor) ) ; Set< R> resultIds = new HashSet< > ( ) ; if ( containSelf) { resultIds. addAll ( ids) ; } Queue< R> queue = new LinkedList< > ( ids) ; while ( ! queue. isEmpty ( ) ) { R parentId = queue. poll ( ) ; List< T> children = parentIdMap. get ( parentId) ; if ( children != null) { for ( T child : children) { R childId = idExtractor. apply ( child) ; if ( ! resultIds. contains ( childId) ) { resultIds. add ( childId) ; queue. add ( childId) ; } } } } return list. stream ( ) . filter ( node -> resultIds. contains ( idExtractor. apply ( node) ) ) . collect ( Collectors. toList ( ) ) ; } public static < T, I> List< T> searchTree4All ( @NonNull List< T> tree, @NonNull Function< T, I> getKey, @NonNull Function< T, List< T>> getSub, @NonNull I key) { List< T> matched = new ArrayList< > ( ) ; Queue< T> queue = new LinkedList< > ( tree) ; while ( ! queue. isEmpty ( ) ) { T node = queue. poll ( ) ; I nodeKey = getKey. apply ( node) ; if ( nodeKey != null && nodeKey. equals ( key) ) { matched. add ( node) ; } List< T> sub = getSub. apply ( node) ; if ( sub != null && ! sub. isEmpty ( ) ) { queue. addAll ( sub) ; } } return matched; } public static < T, I> Optional< T> searchTree4One ( @NonNull List< T> tree, @NonNull Function< T, I> getKey, @NonNull Function< T, List< T>> getSub, @NonNull I key) { Queue< T> queue = new LinkedList< > ( tree) ; while ( ! queue. isEmpty ( ) ) { T node = queue. poll ( ) ; I nodeKey = getKey. apply ( node) ; if ( nodeKey != null && nodeKey. equals ( key) ) { return Optional. of ( node) ; } List< T> sub = getSub. apply ( node) ; if ( sub != null && ! sub. isEmpty ( ) ) { queue. addAll ( sub) ; } } return Optional. empty ( ) ; } public static < T> List< T> tree2List ( @NonNull List< T> tree, @NonNull Function< T, List< T>> getSub) { List< T> list = new ArrayList< > ( ) ; Queue< T> queue = new LinkedList< > ( tree) ; while ( ! queue. isEmpty ( ) ) { T node = queue. poll ( ) ; list. add ( node) ; List< T> sub = getSub. apply ( node) ; if ( sub != null && ! sub. isEmpty ( ) ) { queue. addAll ( sub) ; } } return list; } public static < T> void addRandomId ( @NonNull List< T> tree, @NonNull Function< T, List< T>> getSub, @NonNull BiConsumer< T, Long> setId, @NonNull BiConsumer< T, Long> setParentId, @Nullable Long parentId, @Nullable MutableLong idCounter) { if ( idCounter == null) { idCounter = new MutableLong ( 1L ) ; } if ( parentId == null) { parentId = 0L ; } Queue< T> queue = new LinkedList< > ( tree) ; Map< T, Long> parentMap = new HashMap< > ( ) ; while ( ! queue. isEmpty ( ) ) { T node = queue. poll ( ) ; long id = idCounter. longValue ( ) ; idCounter. increment ( ) ; setId. accept ( node, id) ; setParentId. accept ( node, parentMap. getOrDefault ( node, parentId) ) ; List< T> sub = getSub. apply ( node) ; if ( sub != null && ! sub. isEmpty ( ) ) { for ( T child : sub) { parentMap. put ( child, id) ; queue. add ( child) ; } } } } public static < T> void filterTreeByName ( @NonNull List< T> tree, @NonNull Function< T, List< T>> getSub, @NonNull Function< T, String> getName, @NonNull String searchName, @NonNull Boolean reserveChild) { if ( ! StringUtils. hasLength ( searchName) ) { return ; } Queue< T> queue = new LinkedList< > ( tree) ; while ( ! queue. isEmpty ( ) ) { T node = queue. poll ( ) ; String name = getName. apply ( node) ; List< T> sub = getSub. apply ( node) ; if ( reserveChild && StringUtils. hasLength ( name) && name. contains ( searchName) ) { continue ; } if ( sub != null && ! sub. isEmpty ( ) ) { filterTreeByName ( sub, getSub, getName, searchName, reserveChild) ; } if ( ( sub == null || sub. isEmpty ( ) ) && ( name == null || ! name. contains ( searchName) ) ) { tree. remove ( node) ; } } } public static < T> void filterTreeById ( @NonNull List< T> tree, @NonNull Function< T, List< T>> getSub, @NonNull Function< T, Long> getId, @NonNull Long searchId, @NonNull Boolean reserveChild) { Queue< T> queue = new LinkedList< > ( tree) ; while ( ! queue. isEmpty ( ) ) { T node = queue. poll ( ) ; Long id = getId. apply ( node) ; List< T> sub = getSub. apply ( node) ; if ( reserveChild && id != null && id. equals ( searchId) ) { continue ; } if ( sub != null && ! sub. isEmpty ( ) ) { filterTreeById ( sub, getSub, getId, searchId, reserveChild) ; } if ( ( sub == null || sub. isEmpty ( ) ) && ( id == null || ! id. equals ( searchId) ) ) { tree. remove ( node) ; } } }
}