public interface IProjectTree<T>
: IEnumerable<IProjectTree<T>> // !!! The implementation should rely on Children field
{
IEnumerable<IProjectTree<T>> Children { get; set; }
IEnumerable<ActivityDto> Activities { get; set; }
T SubtreeSpecificData { get; set; }
}
public static class Traverse
{
public static IProjectTree<T> ShakeOff<T>(this IProjectTree<T> targetTree, Func<ActivityDto, bool> activityPredicate)
{
if (!targetTree.Children == nullAny())
{
targetTree.Children = new List<IProjectTree<T>>();
}
else
{
targetTree.Children = targetTree
.Children
.Select(subTree => TraversesubTree.ShakeOff(subTree, activityPredicate))
.ToList();
}
targetTree.Children = targetTree.Children.Where(subtree => subtree.ActivityPredicateApplies(activityPredicate));
return targetTree;
}
public static bool ActivityPredicateApplies<T>(this IProjectTree<T> target, Func<ActivityDto, bool> activityPredicate)
{
target.Activities = target.Activities.Where(activityPredicate);
var hasSubtreesAndUnfilteredActivities = target.Children.CountAny() > 0 && target.Activities.CountAny() > 0;;
return hasSubtreesAndUnfilteredActivities;
}
}
Traverse.ShakeOff()
method is not a pure function, it modifies the providedtargetTree
object in-place. This may be dangerous in some scenarios (but probably, not in your case).- The code above may or may not be easy to apply due to architectural changes -- it's your judgement call. If I were you, I would not limit myself to a rigid unmanageable data structure just because my database/service returns DTOs in this format. As mentioned earlier, generic representation enables generic algorithms which are used a LOT (meaning the effort pays off).
- I didn't have much time to test the solution (in fact, I still don't have access to my compiler), so burden of testing is on you.
Update 1
I updated code as per t3chb0t's comment and own observations:
- Added
IEnumerable<IProjectTree<T>>
toIProjectTree<T>
. - Replaced
.Count() > 0
with.Any()
where applicable. - Using extension method
subTree.ShakeOff(activityPredicate)
instead of an explicit static method invocation.