public static IList <P> PartitionSolveAndMergeBack <T, P>(this IList <T> source, Predicate <T> predicate, Func <IList <T>, IList <P> > matchingPartitionSolver, Func <IList <T>, IList <P> > nonMatchingPartitionSolver) { ArgumentUtility.CheckForNull(source, nameof(source)); ArgumentUtility.CheckForNull(predicate, nameof(predicate)); ArgumentUtility.CheckForNull(matchingPartitionSolver, nameof(matchingPartitionSolver)); ArgumentUtility.CheckForNull(nonMatchingPartitionSolver, nameof(nonMatchingPartitionSolver)); var partitionedSource = new PartitionResults <Tuple <int, T> >(); for (int sourceCnt = 0; sourceCnt < source.Count; sourceCnt++) { var item = source[sourceCnt]; if (predicate(item)) { partitionedSource.MatchingPartition.Add(new Tuple <int, T>(sourceCnt, item)); } else { partitionedSource.NonMatchingPartition.Add(new Tuple <int, T>(sourceCnt, item)); } } var solvedResult = new List <P>(source.Count); if (partitionedSource.MatchingPartition.Any()) { solvedResult.AddRange(matchingPartitionSolver(partitionedSource.MatchingPartition.Select(x => x.Item2).ToList())); } if (partitionedSource.NonMatchingPartition.Any()) { solvedResult.AddRange(nonMatchingPartitionSolver(partitionedSource.NonMatchingPartition.Select(x => x.Item2).ToList())); } var result = Enumerable.Repeat(default(P), source.Count).ToList(); if (solvedResult.Count != source.Count) { return(solvedResult); // either we can throw here or just return solvedResult and ignore! } for (int resultCnt = 0; resultCnt < source.Count; resultCnt++) { if (resultCnt < partitionedSource.MatchingPartition.Count) { result[partitionedSource.MatchingPartition[resultCnt].Item1] = solvedResult[resultCnt]; } else { result[partitionedSource.NonMatchingPartition[resultCnt - partitionedSource.MatchingPartition.Count].Item1] = solvedResult[resultCnt]; } } return(result); }
/// <summary> /// Splits an <see cref="IEnumerable{T}"/> into two partitions, determined by the supplied predicate. Those /// that follow the predicate are returned in the first, with the remaining elements in the second. /// </summary> /// <typeparam name="T">The type of the elements of source.</typeparam> /// <param name="source">The source enumerable to partition.</param> /// <param name="predicate">The predicate applied to filter the items into their partitions.</param> /// <returns>An object containing the matching and nonmatching results.</returns> public static PartitionResults <T> Partition <T>(this IEnumerable <T> source, Predicate <T> predicate) { ArgumentUtility.CheckForNull(source, nameof(source)); ArgumentUtility.CheckForNull(predicate, nameof(predicate)); var results = new PartitionResults <T>(); foreach (var item in source) { if (predicate(item)) { results.MatchingPartition.Add(item); } else { results.NonMatchingPartition.Add(item); } } return(results); }