internal static IList <int> Find(IList <int> values) { if (values == null) { throw new ArgumentNullException("values"); } if (values.Count <= 0) { return(new int[0]); } var maximum = 1; var predecessors = new int[values.Count]; var positions = new int[values.Count]; predecessors[0] = -1; positions[0] = 0; for (var i = 1; i < values.Count; i++) { // We have found an element that extend the longest subsequence found so far. if (values[i] > values[positions[maximum - 1]]) { predecessors[i] = positions[maximum - 1]; positions[maximum] = i; maximum++; } else { var index = LongestIncreasingSubsequence.FindLeastIndex(i, values, positions, maximum); // This is the lowest value found so far. if (index < 0) { predecessors[i] = -1; positions[0] = i; } // We have found an element that could help to find new future subsequences. else { Debug.Assert(index + 1 < maximum); predecessors[i] = positions[index]; positions[index + 1] = i; } } } var result = new int[maximum]; var position = positions[maximum - 1]; for (var i = maximum - 1; i >= 0; i--) { result[i] = values[position]; position = predecessors[position]; } return(result); }
internal static void Diff <T>( this IList <T> source, IList <T> destination, ICollection <T> itemsAdded, ICollection <T> itemsRemoved, ICollection <T> itemsMoved) { if (source == null) { throw new ArgumentNullException("source"); } if (destination == null) { throw new ArgumentNullException("destination"); } // There is nothing to do since the caller is not interested by the result. if ((itemsAdded == null) && (itemsRemoved == null) && (itemsMoved == null)) { return; } var sourceCount = source.Count; var sourcePositions = new Dictionary <T, int>(sourceCount); var sequence = new List <int>(System.Math.Min(sourceCount, destination.Count)); var isAlive = new BitArray(sourceCount, false); var hasNotMoved = default(BitArray); for (var i = 0; i < sourceCount; i++) { sourcePositions.Add(source[i], i); } foreach (var item in destination) { int index; if (sourcePositions.TryGetValue(item, out index)) { isAlive[index] = true; sequence.Add(index); } else if (itemsAdded != null) { itemsAdded.Add(item); } } // We may omit this part of the algorithm if the caller is not interested by the items that have moved. if (itemsMoved != null) { hasNotMoved = new BitArray(sourceCount, false); // The subsequence contains the position of the item that are in the destination collection and that have not moved. foreach (var index in LongestIncreasingSubsequence.Find(sequence)) { hasNotMoved[index] = true; } } // We may omit this part of the algorithm if the caller is not interested by the items that have moved or were removed. if ((itemsRemoved != null) || (itemsMoved != null)) { for (var i = 0; i < sourceCount; i++) { if (isAlive[i]) { // We check if the move collection is not null first because the bit array is null when the move collection is null. if ((itemsMoved != null) && !hasNotMoved[i]) { itemsMoved.Add(source[i]); } } else if (itemsRemoved != null) { itemsRemoved.Add(source[i]); } } } }