This is not “well known,” but rather something that I just came up with.
Remove all elements of the original that are not in the desired list; add each delete operation to the list of operations.Add any items for work that are missing; add each add operation to the list of operations.- Assign each element of the source list a "serial number", which is the position of its counterpart in the desired list. (see snippet below.)
- Find the first element (0 in the original 1 ) and the last element in order from there (1 in the original 2 ).
Remove all elements at positions outside this range and put them in some other temporary list; add each delete operation to the list of operations.- Sort temporary list based on "order number".
Add items in order from the temporary list; add each add operation to the list of operations.- Make sure this newly converted list matches the list.
- Returns a list of operations.
Ex. from step 2:
2013 1234
abcd bcad
Since you can add and remove only those elements that are not added or not added / deleted, I do not think that you can keep the existing order of any sub-segments in a different order than the segment in order 0. That's why all the other elements are deleted in step 4 Since you do not need to add these elements immediately after deletion (based on your example), I assume that it is normal to store them somewhere. So, why not save them in a sorted list and sort them based on the assigned “order number” to determine the order of additions?
If I do not understand your question, you are interested in the order of the operations of adding / removing, so you do not need to actually convert the list (since you already have the converted list); you need steps to create a converted list. Therefore, every time you add or remove in the algorithm, add the "operation" to the list (queue) of operations (for example, operations.Add("remove(a)") ). The algorithm then returns this list of operations.
I wrote a possible implementation in C #. I checked it a bit (screenshots below) and it seemed to work. However, this may not be the best implementation that someone could write.
public static IEnumerable<string> DetermineTransformOrder<T>( IEnumerable<T> original, IEnumerable<T> desired) { // handle the easy case immediately if (original.SequenceEqual(desired)) { return new List<string>(); } List<KeyValuePair<int,T>> workingOriginal = new List<KeyValuePair<int,T>>(); List<T> workingDesired = desired.ToList(); List<string> operations = new List<string>(); //using Queue<> is ok too // load workingOriginal foreach(T element in original) workingOriginal.Add(new KeyValuePair<int, T>(workingDesired.IndexOf(element), element)); //1. Remove all elements from the original that are not in the desired list; // add each remove operation to the list of operations. var tempWorking = new List<KeyValuePair<int,T>>(workingOriginal); foreach (var element in tempWorking) { if (!workingDesired.Contains(element.Value)) { workingOriginal.Remove(element); operations.Add("remove(" + element.Value.ToString() + ")"); } } //2. Add any elements to working that are missing; // add each add operation to the list of operations. tempWorking = new List<KeyValuePair<int,T>>(workingOriginal); foreach(T element in workingDesired) { if(!workingOriginal.Exists(x=>x.Value.Equals(element))) { workingOriginal.Add(new KeyValuePair<int, T>(workingDesired.IndexOf(element), element)); operations.Add("add("+element+")"); } } //3. Assign to each element of the original list a "order number" // which is the position of its analog in the desired list. // note: already done above. would have done it here, but // KeyValuePair.Key is read-only. //4. Find the first element (0 at original[1]) and the // last element in order from there (1 at original[2]). int indexOfFirstElement = workingOriginal.FindIndex(x => x.Key == 0); int indexOfLastElement = indexOfFirstElement; // move to index of last in-order element for (int i = indexOfLastElement + 1; i < workingOriginal.Count && workingOriginal[i - 1].Key + 1 == workingOriginal[i].Key; i++, indexOfLastElement++) ; //5. Remove all elements at positions outside of this range and put them in some // other temporary list; add each remove operation to the list of operations. List<KeyValuePair<int, T>> temporary = new List<KeyValuePair<int, T>>(); var inOrderElements = workingOriginal.GetRange( indexOfFirstElement, indexOfLastElement - indexOfFirstElement + 1); var outOfOrderElements = new List<KeyValuePair<int, T>>( workingOriginal.Except(inOrderElements)); foreach (var element in outOfOrderElements) { workingOriginal.Remove(element); temporary.Add(element); operations.Add("remove(" + element.Value.ToString() + ")"); } //6. Sort the temporary list based on the "order number". temporary.Sort((x, y) => { return x.Key.CompareTo(y.Key); });



source share