public static List<IItem> delete(final FastAdapter fastAdapter, final ExpandableExtension expandableExtension, Collection<Long> identifiersToDelete, boolean notifyParent, boolean deleteEmptyHeaders) {
        List<IItem> deleted = new ArrayList<>();
        if (identifiersToDelete == null || identifiersToDelete.size() == 0) {
            return deleted;
        }

        // we use a LinkedList, because this has performance advantages when modifying the listIterator during iteration!
        // Modifying list is O(1)
        LinkedList<Long> identifiers = new LinkedList<>(identifiersToDelete);

        // we delete item per item from the adapter directly or from the parent
        // if keepEmptyHeaders is false, we add empty headers to the selected items set via the iterator, so that they are processed in the loop as well
        IItem item, parent;
        int pos, parentPos;
        boolean expanded;
        Long identifier;
        ListIterator<Long> it = identifiers.listIterator();
        while (it.hasNext()) {
            identifier = it.next();

            pos = fastAdapter.getPosition(identifier);
            item = fastAdapter.getItem(pos);

            // search for parent - if we find one, we remove the item from the parent's subitems directly
            parent = getParent(item);
            if (parent != null) {
                parentPos = fastAdapter.getPosition(parent);
                boolean success = ((IExpandable) parent).getSubItems().remove(item);
//                Log.d("DELETE", "success=" + success + " | deletedId=" + item.getIdentifier() + " | parentId=" + parent.getIdentifier() + " (sub items: " + ((IExpandable) parent).getSubItems().size() + ") | parentPos=" + parentPos);

                // check if parent is expanded and notify the adapter about the removed item, if necessary (only if parent is visible)
                if (parentPos != -1 && ((IExpandable) parent).isExpanded()) {
                    expandableExtension.notifyAdapterSubItemsChanged(parentPos, ((IExpandable) parent).getSubItems().size() + 1);
                }

                // if desired, notify the parent about it's changed items (only if parent is visible!)
                if (parentPos != -1 && notifyParent) {
                    expanded = ((IExpandable) parent).isExpanded();
                    fastAdapter.notifyAdapterItemChanged(parentPos);
                    // expand the item again if it was expanded before calling notifyAdapterItemChanged
                    if (expanded) {
                        expandableExtension.expand(parentPos);
                    }
                }

                deleted.add(item);

                if (deleteEmptyHeaders && ((IExpandable) parent).getSubItems().size() == 0) {
                    it.add(parent.getIdentifier());
                    it.previous();
                }
            } else if (pos != -1) {
                // if we did not find a parent, we remove the item from the adapter
                IAdapter adapter = fastAdapter.getAdapter(pos);
                boolean success = false;
                if (adapter instanceof IItemAdapter) {
                    success = ((IItemAdapter) adapter).remove(pos) != null;
                    if (success) {
                        fastAdapter.notifyAdapterItemRemoved(pos);
                    }
                }
                boolean isHeader = item instanceof IExpandable && ((IExpandable) item).getSubItems() != null;
//                Log.d("DELETE", "success=" + success + " | deletedId=" + item.getIdentifier() + "(" + (isHeader ? "EMPTY HEADER" : "ITEM WITHOUT HEADER") + ")");
                deleted.add(item);
            }
        }

//        Log.d("DELETE", "deleted (incl. empty headers): " + deleted.size());

        return deleted;
    }
public static List < IItem > delete ( final FastAdapter fastAdapter , final ExpandableExtension expandableExtension , Collection < Long > identifiersToDelete , boolean notifyParent , boolean deleteEmptyHeaders ) { List < IItem > deleted = new ArrayList < > ( ) ; if ( identifiersToDelete == null || identifiersToDelete . size ( ) == 0 ) { return deleted ; } LinkedList < Long > identifiers = new LinkedList < > ( identifiersToDelete ) ; IItem item , parent ; int pos , parentPos ; boolean expanded ; Long identifier ; ListIterator < Long > it = identifiers . listIterator ( ) ; while ( it . hasNext ( ) ) { identifier = it . next ( ) ; pos = fastAdapter . getPosition ( identifier ) ; item = fastAdapter . getItem ( pos ) ; parent = getParent ( item ) ; if ( parent != null ) { parentPos = fastAdapter . getPosition ( parent ) ; boolean success = ( ( IExpandable ) parent ) . getSubItems ( ) . remove ( item ) ; if ( parentPos != - 1 && ( ( IExpandable ) parent ) . isExpanded ( ) ) { expandableExtension . notifyAdapterSubItemsChanged ( parentPos , ( ( IExpandable ) parent ) . getSubItems ( ) . size ( ) + 1 ) ; } if ( parentPos != - 1 && notifyParent ) { expanded = ( ( IExpandable ) parent ) . isExpanded ( ) ; fastAdapter . notifyAdapterItemChanged ( parentPos ) ; if ( expanded ) { expandableExtension . expand ( parentPos ) ; } } deleted . add ( item ) ; if ( deleteEmptyHeaders && ( ( IExpandable ) parent ) . getSubItems ( ) . size ( ) == 0 ) { it . add ( parent . getIdentifier ( ) ) ; it . previous ( ) ; } } else if ( pos != - 1 ) { IAdapter adapter = fastAdapter . getAdapter ( pos ) ; boolean success = false ; if ( adapter instanceof IItemAdapter ) { success = ( ( IItemAdapter ) adapter ) . remove ( pos ) != null ; if ( success ) { fastAdapter . notifyAdapterItemRemoved ( pos ) ; } } boolean isHeader = item instanceof IExpandable && ( ( IExpandable ) item ) . getSubItems ( ) != null ; deleted . add ( item ) ; } } return deleted ; }
deletes all items in identifiersToDelete collection from the adapter respecting if there are sub items or not
subitems are removed from their parents sublists, main items are directly removed

@param fastAdapter         the adapter to remove the items from
@param identifiersToDelete ids of items to remove
@param notifyParent        if true, headers of removed items will be notified about the change of their child items
@param deleteEmptyHeaders  if true, empty headers will be removed from the adapter
@return List of items that have been removed from the adapter