public IOrderedEnumerable <TElement> CreateOrderedEnumerable <TNewKey>(Func <TElement, TNewKey> keySelector, IComparer <TNewKey> comparer, bool descending) { comparer = comparer ?? Comparer <TNewKey> .Default; if (descending) { comparer = comparer.Reverse(); } var compoundComparer = new CustomComparer <(TKey, TNewKey)>(Compare); return(new OrderedEnumerable <TElement, (TKey, TNewKey)>(_source, CompoundKeySelector, compoundComparer)); (TKey, TNewKey) CompoundKeySelector(TElement item) { return(_keySelector(item), keySelector(item)); } int Compare((TKey, TNewKey) x, (TKey, TNewKey) y) { var check = _comparer.Compare(x.Item1, y.Item1); if (check == 0) { return(comparer.Compare(x.Item2, y.Item2)); } return(check); } }
/// <summary> /// Sorts the elements of a sequence in descending order according to a key. /// Unlike standard Linq NOT a stable sort. /// </summary> /// <param name="source">A sequence of values to order.</param> /// <param name="keySelector">A function to extract a key from an element.</param> /// <param name="comparer">A Comparer to compare keys.</param> /// <returns>A sequence whose elements are ordered according to a key</returns> public static TSource[] OrderByDescendingF <TSource, TKey>(this TSource[] source, Func <TSource, TKey> keySelector, IComparer <TKey> comparer = null) { if (source == null) { throw Error.ArgumentNull(nameof(source)); } if (keySelector == null) { throw Error.ArgumentNull("keySelector"); } if (comparer == null) { comparer = Comparer <TKey> .Default; } TKey[] keys = new TKey[source.Length]; for (int i = 0; i < keys.Length; i++) { keys[i] = keySelector(source[i]); } TSource[] result = (TSource[])source.Clone(); Array.Sort(keys, result, comparer.Reverse()); return(result); }
public IOrderedEnumerable <TElement> CreateOrderedEnumerable <TNewKey>(Func <TElement, TNewKey> keySelector, IComparer <TNewKey> comparer, bool descending) { if (keySelector == null) { throw new ArgumentNullException(nameof(keySelector)); } comparer = comparer ?? Comparer <TNewKey> .Default; if (descending) { comparer = comparer.Reverse(); } var compoundComparer = new CustomComparer <KeyValuePair <TKey, TNewKey> >(Compare); return(new OrderedEnumerable <TElement, KeyValuePair <TKey, TNewKey> >(_source, CompoundKeySelector, compoundComparer)); KeyValuePair <TKey, TNewKey> CompoundKeySelector(TElement item) { return(new KeyValuePair <TKey, TNewKey>(_keySelector(item), keySelector(item))); } int Compare(KeyValuePair <TKey, TNewKey> x, KeyValuePair <TKey, TNewKey> y) { var check = _comparer.Compare(x.Key, y.Key); return(check == 0 ? comparer.Compare(x.Value, y.Value) : check); } }
public IOrderedEnumerable <TElement> CreateOrderedEnumerable <TNewKey>(Func <TElement, TNewKey> keySelector, IComparer <TNewKey> comparer, bool descending) { comparer = comparer ?? Comparer <TNewKey> .Default; if (descending) { comparer = comparer.Reverse(); } return(new OrderedEnumerable <TElement, TNewKey>(_source, keySelector, comparer)); }
public OrderedEnumerable(IEnumerable <TElement> source, Func <TElement, TKey> keySelector, IComparer <TKey> comparer, bool descending) { _comparer = comparer ?? Comparer <TKey> .Default; if (descending) { _comparer = _comparer.Reverse(); } _source = source ?? throw new ArgumentNullException(nameof(source)); _keySelector = keySelector ?? throw new ArgumentNullException(nameof(keySelector)); }
public void SubstitutesCompareDefaultForNull() { IComparer <int> source = null; var comparer = source.Reverse(); Assert.Equal(ComparerBuilder.For <int>().Default().Reverse().ToString(), comparer.ToString()); var list = Enumerable.Range(0, 5).ToList(); list.Sort(comparer); Assert.Equal(new[] { 4, 3, 2, 1, 0 }, list); }
public int ShouldExtendComparerByReverseMethod(IComparer <object> comparer) { // given var obj1 = new object(); var obj2 = new object(); // when var reverse = comparer.Reverse(); // then return(reverse.Compare(obj1, obj2)); }
public void SubstitutesCompareDefaultForNull() { IComparer <int> source = null; var comparer = source.Reverse(); Assert.AreSame(Compare <int> .Default(), (comparer as ReverseComparer <int>).Source); var list = Enumerable.Range(0, 5).ToList(); list.Sort(comparer); CollectionAssert.AreEqual(new[] { 4, 3, 2, 1, 0 }, list); }
/// <summary> /// Returns a comparer that uses another comparer if the source comparer determines the objects are equal. /// </summary> /// <typeparam name="T">The type of objects being compared.</typeparam> /// <param name="source">The source comparer. If this is <c>null</c>, the default comparer is used.</param> /// <param name="thenBy">The comparer that is used if <paramref name="source"/> determines the objects are equal. If this is <c>null</c>, the default comparer is used.</param> /// <param name="descending">A value indicating whether the sorting is done in descending order. If <c>false</c> (the default), then the sort is in ascending order.</param> /// <returns>A comparer that uses another comparer if the source comparer determines the objects are equal.</returns> public static IFullComparer <T> ThenBy <T>(this IComparer <T> source, IComparer <T> thenBy, bool descending = false) => new CompoundComparer <T>(source, descending ? thenBy.Reverse() : thenBy);
/// <summary> /// The implementaiton of SEARCH-LAYER(q, ep, ef, lc) algorithm. /// Article: Section 4. Algorithm 2. /// </summary> /// <param name="entryPointId">The identifier of the entry point for the search.</param> /// <param name="targetCosts">The traveling costs for the search target.</param> /// <param name="resultList">The list of identifiers of the nearest neighbours at the level.</param> /// <param name="layer">The layer to perform search at.</param> /// <param name="k">The number of the nearest neighbours to get from the layer.</param> internal void RunKnnAtLayer(int entryPointId, TravelingCosts <int, TDistance> targetCosts, IList <int> resultList, int layer, int k) { /* * v ← ep // set of visited elements * C ← ep // set of candidates * W ← ep // dynamic list of found nearest neighbors * while │C│ > 0 * c ← extract nearest element from C to q * f ← get furthest element from W to q * if distance(c, q) > distance(f, q) * break // all elements in W are evaluated * for each e ∈ neighbourhood(c) at layer lc // update C and W * if e ∉ v * v ← v ⋃ e * f ← get furthest element from W to q * if distance(e, q) < distance(f, q) or │W│ < ef * C ← C ⋃ e * W ← W ⋃ e * if │W│ > ef * remove furthest element from W to q * return W */ // prepare tools IComparer <int> fartherIsOnTop = targetCosts; IComparer <int> closerIsOnTop = fartherIsOnTop.Reverse(); // prepare collections // TODO: Optimize by providing buffers var resultHeap = new BinaryHeap <int>(resultList, fartherIsOnTop); var expansionHeap = new BinaryHeap <int>(this.expansionBuffer, closerIsOnTop); resultHeap.Push(entryPointId); expansionHeap.Push(entryPointId); this.visitedSet.Add(entryPointId); // run bfs while (expansionHeap.Buffer.Count > 0) { // get next candidate to check and expand var toExpandId = expansionHeap.Pop(); var farthestResultId = resultHeap.Buffer[0]; if (DistanceUtils.Gt(targetCosts.From(toExpandId), targetCosts.From(farthestResultId))) { // the closest candidate is farther than farthest result break; } // expand candidate var neighboursIds = this.core.Nodes[toExpandId][layer]; for (int i = 0; i < neighboursIds.Count; ++i) { int neighbourId = neighboursIds[i]; if (!this.visitedSet.Contains(neighbourId)) { // enque perspective neighbours to expansion list farthestResultId = resultHeap.Buffer[0]; if (resultHeap.Buffer.Count < k || DistanceUtils.Lt(targetCosts.From(neighbourId), targetCosts.From(farthestResultId))) { expansionHeap.Push(neighbourId); resultHeap.Push(neighbourId); if (resultHeap.Buffer.Count > k) { resultHeap.Pop(); } } // update visited list this.visitedSet.Add(neighbourId); } } } this.expansionBuffer.Clear(); this.visitedSet.Clear(); }
/// <summary> /// Returns a comparer that uses another comparer if the source comparer determines the objects are equal. /// </summary> /// <typeparam name="T">The type of objects being compared.</typeparam> /// <param name="source">The source comparer. If this is <c>null</c>, the default comparer is used.</param> /// <param name="thenBy">The comparer that is used if <paramref name="source"/> determines the objects are equal. If this is <c>null</c>, the default comparer is used.</param> /// <param name="descending">A value indicating whether the sorting is done in descending order. If <c>false</c> (the default), then the sort is in ascending order.</param> /// <returns>A comparer that uses another comparer if the source comparer determines the objects are equal.</returns> public static IFullComparer <T> ThenBy <T>(this IComparer <T> source, IComparer <T> thenBy, bool descending = false) { Contract.Ensures(Contract.Result <IFullComparer <T> >() != null); return(new CompoundComparer <T>(source, descending ? thenBy.Reverse() : thenBy)); }
/// <summary> /// The implementaiton of SEARCH-LAYER(q, ep, ef, lc) algorithm. /// Article: Section 4. Algorithm 2. /// </summary> /// <param name="entryPoint">The entry point for the search.</param> /// <param name="destination">The search target.</param> /// <param name="k">The number of the nearest neighbours to get from the layer.</param> /// <param name="level">Level of the layer.</param> /// <returns>The list of the nearest neighbours at the level.</returns> private static IList <Node> KNearestAtLevel(Node entryPoint, Node destination, int k, int level) { /* * v ← ep // set of visited elements * C ← ep // set of candidates * W ← ep // dynamic list of found nearest neighbors * while │C│ > 0 * c ← extract nearest element from C to q * f ← get furthest element from W to q * if distance(c, q) > distance(f, q) * break // all elements in W are evaluated * for each e ∈ neighbourhood(c) at layer lc // update C and W * if e ∉ v * v ← v ⋃ e * f ← get furthest element from W to q * if distance(e, q) < distance(f, q) or │W│ < ef * C ← C ⋃ e * W ← W ⋃ e * if │W│ > ef * remove furthest element from W to q * return W */ // prepare tools IComparer <Node> closerIsLess = destination.TravelingCosts; IComparer <Node> fartherIsLess = closerIsLess.Reverse(); // prepare heaps var resultHeap = new BinaryHeap <Node>(new List <Node>(k + 1) { entryPoint }, closerIsLess); var expansionHeap = new BinaryHeap <Node>(new List <Node>() { entryPoint }, fartherIsLess); // run bfs var visited = new HashSet <int>() { entryPoint.Id }; while (expansionHeap.Buffer.Any()) { // get next candidate to check and expand var toExpand = expansionHeap.Pop(); var farthestResult = resultHeap.Buffer.First(); if (DGt(destination.TravelingCosts.From(toExpand), destination.TravelingCosts.From(farthestResult))) { // the closest candidate is farther than farthest result break; } // expand candidate foreach (var neighbour in toExpand.GetConnections(level)) { if (!visited.Contains(neighbour.Id)) { // enque perspective neighbours to expansion list farthestResult = resultHeap.Buffer.First(); if (resultHeap.Buffer.Count < k || DLt(destination.TravelingCosts.From(neighbour), destination.TravelingCosts.From(farthestResult))) { expansionHeap.Push(neighbour); resultHeap.Push(neighbour); if (resultHeap.Buffer.Count > k) { resultHeap.Pop(); } } // update visited list visited.Add(neighbour.Id); } } } return(resultHeap.Buffer); }
/// <inheritdoc /> public override IList <Node> SelectBestForConnecting(IList <Node> candidates) { /* * q ← this * R ← ∅ // result * W ← C // working queue for the candidates * if expandCandidates // expand candidates * for each e ∈ C * for each eadj ∈ neighbourhood(e) at layer lc * if eadj ∉ W * W ← W ⋃ eadj * * Wd ← ∅ // queue for the discarded candidates * while │W│ gt 0 and │R│ lt M * e ← extract nearest element from W to q * if e is closer to q compared to any element from R * R ← R ⋃ e * else * Wd ← Wd ⋃ e * * if keepPrunedConnections // add some of the discarded connections from Wd * while │Wd│ gt 0 and │R│ lt M * R ← R ⋃ extract nearest element from Wd to q * * return R */ IComparer <Node> closerIsLess = this.TravelingCosts; IComparer <Node> fartherIsLess = closerIsLess.Reverse(); var resultHeap = new BinaryHeap <Node>(new List <Node>(GetM(this.Parameters.M, this.MaxLevel) + 1), closerIsLess); var candidatesHeap = new BinaryHeap <Node>(candidates, fartherIsLess); // expand candidates option is enabled if (this.Parameters.ExpandBestSelection) { var candidatesIds = new HashSet <int>(candidates.Select(c => c.Id)); foreach (var neighbour in this.GetConnections(this.MaxLevel)) { if (!candidatesIds.Contains(neighbour.Id)) { candidatesHeap.Push(neighbour); candidatesIds.Add(neighbour.Id); } } } // main stage of moving candidates to result var discardedHeap = new BinaryHeap <Node>(new List <Node>(candidatesHeap.Buffer.Count), fartherIsLess); while (candidatesHeap.Buffer.Any() && resultHeap.Buffer.Count < GetM(this.Parameters.M, this.MaxLevel)) { var candidate = candidatesHeap.Pop(); var farestResult = resultHeap.Buffer.FirstOrDefault(); if (farestResult == null || DLt(this.TravelingCosts.From(candidate), this.TravelingCosts.From(farestResult))) { resultHeap.Push(candidate); } else if (this.Parameters.KeepPrunedConnections) { discardedHeap.Push(candidate); } } // keep pruned option is enabled if (this.Parameters.KeepPrunedConnections) { while (discardedHeap.Buffer.Any() && resultHeap.Buffer.Count < GetM(this.Parameters.M, this.MaxLevel)) { resultHeap.Push(discardedHeap.Pop()); } } return(resultHeap.Buffer); }
/// <inheritdoc/> internal override List <int> SelectBestForConnecting(List <int> candidatesIds, TravelingCosts <int, TDistance> travelingCosts, int layer) { /* * q ← this * R ← ∅ // result * W ← C // working queue for the candidates * if expandCandidates // expand candidates * for each e ∈ C * for each eadj ∈ neighbourhood(e) at layer lc * if eadj ∉ W * W ← W ⋃ eadj * * Wd ← ∅ // queue for the discarded candidates * while │W│ gt 0 and │R│ lt M * e ← extract nearest element from W to q * if e is closer to q compared to any element from R * R ← R ⋃ e * else * Wd ← Wd ⋃ e * * if keepPrunedConnections // add some of the discarded connections from Wd * while │Wd│ gt 0 and │R│ lt M * R ← R ⋃ extract nearest element from Wd to q * * return R */ IComparer <int> fartherIsOnTop = travelingCosts; IComparer <int> closerIsOnTop = fartherIsOnTop.Reverse(); var layerM = GetM(layer); var resultHeap = new BinaryHeap <int>(new List <int>(layerM + 1), fartherIsOnTop); var candidatesHeap = new BinaryHeap <int>(candidatesIds, closerIsOnTop); // expand candidates option is enabled if (GraphCore.Parameters.ExpandBestSelection) { var visited = new HashSet <int>(candidatesHeap.Buffer); var toAdd = new HashSet <int>(); foreach (var candidateId in candidatesHeap.Buffer) { var candidateNeighborsIDs = GraphCore.Nodes[candidateId][layer]; foreach (var candidateNeighbourId in candidateNeighborsIDs) { if (!visited.Contains(candidateNeighbourId)) { toAdd.Add(candidateNeighbourId); visited.Add(candidateNeighbourId); } } } foreach (var id in toAdd) { candidatesHeap.Push(id); } } // main stage of moving candidates to result var discardedHeap = new BinaryHeap <int>(new List <int>(candidatesHeap.Buffer.Count), closerIsOnTop); while (candidatesHeap.Buffer.Any() && resultHeap.Buffer.Count < layerM) { var candidateId = candidatesHeap.Pop(); var farestResultId = resultHeap.Buffer.FirstOrDefault(); if (!resultHeap.Buffer.Any() || DistanceUtils.LowerThan(travelingCosts.From(candidateId), travelingCosts.From(farestResultId))) { resultHeap.Push(candidateId); } else if (GraphCore.Parameters.KeepPrunedConnections) { discardedHeap.Push(candidateId); } } // keep pruned option is enabled if (GraphCore.Parameters.KeepPrunedConnections) { while (discardedHeap.Buffer.Any() && resultHeap.Buffer.Count < layerM) { resultHeap.Push(discardedHeap.Pop()); } } return(resultHeap.Buffer); }
/// <summary> /// Creates a descending key comparer. /// </summary> /// <typeparam name="TKey">The type of key objects being compared.</typeparam> /// <param name="selector">The key selector. May not be <c>null</c>.</param> /// <param name="keyComparer">The key comparer. The returned comparer applies this key comparer in reverse. Defaults to <c>null</c>. If this is <c>null</c>, the default comparer is used.</param> /// <param name="allowNulls">A value indicating whether <c>null</c> values are passed to <paramref name="selector"/>. If <c>false</c>, then <c>null</c> values are considered less than any non-<c>null</c> values and are not passed to <paramref name="selector"/>.</param> /// <returns>A key comparer.</returns> public static IFullComparer <T> OrderByDescending <TKey>(Func <T, TKey> selector, IComparer <TKey> keyComparer = null, bool allowNulls = false) { Contract.Requires(selector != null); Contract.Ensures(Contract.Result <IFullComparer <T> >() != null); return(OrderBy <TKey>(selector, keyComparer.Reverse(), allowNulls)); }