public IChangeSet <TObject, TKey> Reorder() { var result = new List <Change <TObject, TKey> >(); if (_optimisations.HasFlag(SortOptimisations.IgnoreEvaluates)) { //reorder entire sequence and do not calculate moves _list = _list.OrderBy(kv => kv, _comparer).ToList(); } else { var index = -1; var sorted = _list.OrderBy(t => t, _comparer).ToList(); var unsortedCache = _list.Select((kvp, idx) => new { kvp, idx }).ToDictionary(o => o.kvp, o => o.idx); foreach (var item in sorted) { index++; var oldPos = unsortedCache[item]; if (oldPos == index) { continue; } result.Add(new Change <TObject, TKey>(item.Key, item.Value, index, oldPos)); } _list = sorted; } return(new ChangeSet <TObject, TKey>(result)); }
public IChangeSet <TObject, TKey> Reorder() { var result = new List <Change <TObject, TKey> >(); if (_optimisations.HasFlag(SortOptimisations.IgnoreEvaluates)) { //reorder entire sequence and do not calculate moves _list = new LinkedList <KeyValuePair <TKey, TObject> >(_list.OrderBy(kv => kv, _comparer)); } else { var sorted = _list.OrderBy(t => t, _comparer).Select((item, i) => Tuple.Create(item, i)).ToList(); var oldByKey = _list.Select((item, i) => Tuple.Create(item, i)).ToDictionary(x => x.Item1.Key, x => x.Item2); foreach (var item in sorted) { var currentItem = item.Item1; var currentIndex = item.Item2; var previousIndex = oldByKey[currentItem.Key]; if (currentIndex != previousIndex) { result.Add(new Change <TObject, TKey>(currentItem.Key, currentItem.Value, currentIndex, previousIndex)); } } _list = new LinkedList <KeyValuePair <TKey, TObject> >(sorted.Select(s => s.Item1)); } return(new ChangeSet <TObject, TKey>(result)); }
public IChangeSet <TObject, TKey> Reorder() { var result = new List <Change <TObject, TKey> >(); if (_optimisations.HasFlag(SortOptimisations.IgnoreEvaluates)) { //reorder entire sequence and do not calculate moves _list = _list.OrderBy(kv => kv, _comparer).ToList(); } else { int index = -1; var sorted = _list.OrderBy(t => t, _comparer).ToList(); foreach (var item in sorted) { KeyValuePair <TKey, TObject> current = item; index++; //Cannot use binary search as Resort is implicit of a mutable change KeyValuePair <TKey, TObject> existing = _list[index]; var areequal = EqualityComparer <TKey> .Default.Equals(current.Key, existing.Key); if (areequal) { continue; } var old = _list.IndexOf(current); _list.RemoveAt(old); _list.Insert(index, current); result.Add(new Change <TObject, TKey>(current.Key, current.Value, index, old)); } } return(new ChangeSet <TObject, TKey>(result)); }
/// <summary> /// Dynamic calculation of moved items which produce a result which can be enumerated through in order. /// </summary> /// <param name="changes">The change set.</param> /// <returns>A change set with the calculations.</returns> public IChangeSet <TObject, TKey> Calculate(IChangeSet <TObject, TKey> changes) { var result = new List <Change <TObject, TKey> >(changes.Count); var refreshes = new List <Change <TObject, TKey> >(changes.Refreshes); foreach (var u in changes) { var current = new KeyValuePair <TKey, TObject>(u.Key, u.Current); switch (u.Reason) { case ChangeReason.Add: { var position = GetInsertPositionBinary(current); List.Insert(position, current); result.Add(new Change <TObject, TKey>(ChangeReason.Add, u.Key, u.Current, position)); } break; case ChangeReason.Update: { var previous = new KeyValuePair <TKey, TObject>(u.Key, u.Previous.Value); var old = GetCurrentPosition(previous); List.RemoveAt(old); var newPosition = GetInsertPositionBinary(current); List.Insert(newPosition, current); result.Add(new Change <TObject, TKey>(ChangeReason.Update, u.Key, u.Current, u.Previous, newPosition, old)); } break; case ChangeReason.Remove: { var position = GetCurrentPosition(current); List.RemoveAt(position); result.Add(new Change <TObject, TKey>(ChangeReason.Remove, u.Key, u.Current, position)); } break; case ChangeReason.Refresh: { refreshes.Add(u); result.Add(u); } break; } } // for evaluates, check whether the change forces a new position var evaluates = refreshes.OrderByDescending(x => new KeyValuePair <TKey, TObject>(x.Key, x.Current), _comparer).ToList(); if (evaluates.Count != 0 && _optimisations.HasFlag(SortOptimisations.IgnoreEvaluates)) { // reorder entire sequence and do not calculate moves List = List.OrderBy(kv => kv, _comparer).ToList(); } else { // calculate moves. Very expensive operation // TODO: Try and make this better foreach (var u in evaluates) { var current = new KeyValuePair <TKey, TObject>(u.Key, u.Current); var old = List.IndexOf(current); if (old == -1) { continue; } int newPosition = GetInsertPositionLinear(List, current); if (old < newPosition) { newPosition--; } if (old == newPosition) { continue; } List.RemoveAt(old); List.Insert(newPosition, current); result.Add(new Change <TObject, TKey>(u.Key, u.Current, newPosition, old)); } } return(new ChangeSet <TObject, TKey>(result)); }