Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.Netron/3.0.2672.12446/Netron.Diagramming.Core-3.0.2672.12446/Utils/Algorithms.cs @ 4019

Last change on this file since 4019 was 2768, checked in by mkommend, 15 years ago

added solution folders and sources for the netron library (ticket #867)

File size: 23.9 KB
Line 
1//******************************
2// Written by Peter Golde
3// Copyright (connector) 2004-2005, Wintellect
4//
5// Use and restribution of this code is subject to the license agreement
6// contained in the file "License.txt" accompanying this file.
7//******************************
8
9using System;
10using System.Collections;
11using System.Collections.Generic;
12
13#pragma warning disable 419  // Ambigious cref in XML comment
14
15namespace Netron.Diagramming.Core
16{
17
18    /// <summary>
19    /// Algorithms contains a number of static methods that implement
20    /// algorithms that work on collections. Most of the methods deal with
21    /// the standard generic collection interfaces such as IEnumerable&lt;T&gt;,
22    /// ICollection&lt;T&gt; and IList&lt;T&gt;.
23    /// </summary>
24    public static class Algorithms
25    {
26
27        /// <summary>
28        /// Create an IEnumerable that enumerates an array. Make sure that only enumerable stuff
29        /// is used and no downcasts to ICollection are taken advantage of.
30        /// </summary>
31        /// <param name="array">An array.</param>
32        /// <returns>An IEnumerable cast of the array</returns>
33        /// <typeparam name="T">a </typeparam>
34        /// <example>The following code
35        /// <code>
36        ///
37        /// </code>
38        /// </example>
39        public static IEnumerable<T> EnumerableFromArray<T>(T[] array)
40        {
41            foreach (T t in array)
42                yield return t;
43        }
44
45
46     
47        #region String representations
48
49        /// <summary>
50        /// Gets a string representation of the elements in the collection.
51        /// The string representation starts with "{", has a list of items separated
52        /// by commas (","), and ends with "}". Each item in the collection is
53        /// converted to a string by calling its ToString method (null is represented by "null").
54        /// Contained collections (except strings) are recursively converted to strings by this method.
55        /// </summary>
56        /// <param name="collection">A collection to get the string representation of.</param>
57        /// <returns>The string representation of the collection. If <paramref name="collection"/> is null, then the string "null" is returned.</returns>
58        internal static string ToString<T>(IEnumerable<T> collection)
59        {
60            return collection.GetType().Name;// ToString(collection);
61        }
62
63   
64
65        /// <summary>
66        /// Gets a string representation of the mappings in a dictionary.
67        /// The string representation starts with "{", has a list of mappings separated
68        /// by commas (", "), and ends with "}". Each mapping is represented
69        /// by "key->value". Each key and value in the dictionary is
70        /// converted to a string by calling its ToString method (null is represented by "null").
71        /// Contained collections (except strings) are recursively converted to strings by this method.
72        /// </summary>
73        /// <param name="dictionary">A dictionary to get the string representation of.</param>
74        /// <returns>The string representation of the collection, or "null"
75        /// if <paramref name="dictionary"/> is null.</returns>
76        internal static string ToString<TKey, TValue>(IDictionary<TKey, TValue> dictionary)
77        {
78            bool firstItem = true;
79
80            if (dictionary == null)
81                return "null";
82
83            System.Text.StringBuilder builder = new System.Text.StringBuilder();
84
85            builder.Append("{");
86
87            // Call ToString on each item and put it in.
88            foreach (KeyValuePair<TKey, TValue> pair in dictionary) {
89                if (!firstItem)
90                    builder.Append(", ");
91
92                if (pair.Key == null)
93                    builder.Append("null");
94               
95                else
96                    builder.Append(pair.Key.ToString());
97
98                builder.Append("->");
99
100                if (pair.Value == null)
101                    builder.Append("null");
102               
103                else
104                    builder.Append(pair.Value.ToString());
105
106
107                firstItem = false;
108            }
109
110            builder.Append("}");
111            return builder.ToString();
112        }
113
114        #endregion String representations
115
116 
117
118 
119
120   
121
122        #region Predicate operations
123
124        /// <summary>
125        /// Determines if a collection contains any item that satisfies the condition
126        /// defined by <paramref name="predicate"/>.
127        /// </summary>
128        /// <param name="collection">The collection to check all the items in.</param>
129        /// <param name="predicate">A delegate that defines the condition to check for.</param>
130        /// <returns>True if the collection contains one or more items that satisfy the condition
131        /// defined by <paramref name="predicate"/>. False if the collection does not contain
132        /// an item that satisfies <paramref name="predicate"/>.</returns>
133        internal static bool Exists<T>(IEnumerable<T> collection, Predicate<T> predicate)
134        {
135            if (collection == null)
136                throw new ArgumentNullException("collection");
137            if (predicate == null)
138                throw new ArgumentNullException("predicate");
139
140            foreach (T item in collection) {
141                if (predicate(item))
142                    return true;
143            }
144
145            return false;
146        }
147
148        /// <summary>
149        /// Determines if all of the items in the collection satisfy the condition
150        /// defined by <paramref name="predicate"/>.
151        /// </summary>
152        /// <param name="collection">The collection to check all the items in.</param>
153        /// <param name="predicate">A delegate that defines the condition to check for.</param>
154        /// <returns>True if all of the items in the collection satisfy the condition
155        /// defined by <paramref name="predicate"/>, or if the collection is empty. False if one or more items
156        /// in the collection do not satisfy <paramref name="predicate"/>.</returns>
157        internal static bool TrueForAll<T>(IEnumerable<T> collection, Predicate<T> predicate)
158        {
159            if (collection == null)
160                throw new ArgumentNullException("collection");
161            if (predicate == null)
162                throw new ArgumentNullException("predicate");
163
164            foreach (T item in collection) {
165                if (!predicate(item))
166                    return false;
167            }
168
169            return true;
170        }
171         /*
172        /// <summary>
173        /// Counts the number of items in the collection that satisfy the condition
174        /// defined by <paramref name="predicate"/>.
175        /// </summary>
176        /// <param name="collection">The collection to count items in.</param>
177        /// <param name="predicate">A delegate that defines the condition to check for.</param>
178        /// <returns>The number of items in the collection that satisfy <paramref name="predicate"/>.</returns>
179        public static int CountWhere<T>(IEnumerable<T> collection, Predicate<T> predicate)
180        {
181            if (collection == null)
182                throw new ArgumentNullException("collection");
183            if (predicate == null)
184                throw new ArgumentNullException("predicate");
185
186            int count = 0;
187            foreach (T item in collection)
188            {
189                if (predicate(item))
190                    ++count;
191            }
192
193            return count;
194        }
195        */
196        /// <summary>
197        /// Removes all the items in the collection that satisfy the condition
198        /// defined by <paramref name="predicate"/>.
199        /// </summary>
200        /// <remarks>If the collection if an array or implements IList&lt;T&gt;, an efficient algorithm that
201        /// compacts items is used. If not, then ICollection&lt;T&gt;.Remove is used
202        /// to remove items from the collection. If the collection is an array or fixed-size list,
203        /// the non-removed elements are placed, in order, at the beginning of
204        /// the list, and the remaining list items are filled with a default value (0 or null).</remarks>
205        /// <param name="collection">The collection to check all the items in.</param>
206        /// <param name="predicate">A delegate that defines the condition to check for.</param>
207        /// <returns>Returns a collection of the items that were removed. This collection contains the
208        /// items in the same order that they orginally appeared in <paramref name="collection"/>.</returns>
209        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
210        internal static ICollection<T> RemoveWhere<T>(ICollection<T> collection, Predicate<T> predicate)
211        {
212            if (collection == null)
213                throw new ArgumentNullException("collection");
214            if (predicate == null)
215                throw new ArgumentNullException("predicate");
216         
217
218            IList<T> list = collection as IList<T>;
219            if (list != null) {
220                T item;
221                int i = -1, j = 0;
222                int listCount = list.Count;
223                List<T> removed = new List<T>();
224
225                // Remove item where predicate is true, compressing items to lower in the list. This is much more
226                // efficient than the naive algorithm that uses IList<T>.Remove().
227                while (j < listCount) {
228                    item = list[j];
229                    if (predicate(item)) {
230                        removed.Add(item);
231                    }
232                    else {
233                        ++i;
234                        if (i != j)
235                            list[i] = item;
236                    }
237                    ++j;
238                }
239
240                ++i;
241                if (i < listCount) {
242                    // remove items from the end.
243                    if (list is IList && ((IList)list).IsFixedSize) {
244                        // An array or similar. Null out the last elements.
245                        while (i < listCount)
246                            list[i++] = default(T);
247                    }
248                    else {
249                        // Normal list.
250                        while (i < listCount) {
251                            list.RemoveAt(listCount - 1);
252                            --listCount;
253                        }
254                    }
255                }
256
257                return removed;
258            }
259            else {
260                // We have to copy all the items to remove to a List, because collections can't be modifed
261                // during an enumeration.
262                List<T> removed = new List<T>();
263
264                foreach (T item in collection)
265                    if (predicate(item))
266                        removed.Add(item);
267
268                foreach (T item in removed)
269                    collection.Remove(item);
270
271                return removed;
272            }
273        }
274        /*
275        /// <summary>
276        /// Convert a collection of items by applying a delegate to each item in the collection. The resulting collection
277        /// contains the result of applying <paramref name="converter"/> to each item in <paramref name="sourceCollection"/>, in
278        /// order.
279        /// </summary>
280        /// <typeparam name="TSource">The type of items in the collection to convert.</typeparam>
281        /// <typeparam name="TDest">The type each item is being converted to.</typeparam>
282        /// <param name="sourceCollection">The collection of item being converted.</param>
283        /// <param name="converter">A delegate to the method to call, passing each item in <paramref name="sourceCollection"/>.</param>
284        /// <returns>The resulting collection from applying <paramref name="converter"/> to each item in <paramref name="sourceCollection"/>, in
285        /// order.</returns>
286        /// <exception cref="ArgumentNullException"><paramref name="sourceCollection"/> or <paramref name="converter"/> is null.</exception>
287        public static IEnumerable<TDest> Convert<TSource, TDest>(IEnumerable<TSource> sourceCollection, Converter<TSource, TDest> converter)
288        {
289            if (sourceCollection == null)
290                throw new ArgumentNullException("sourceCollection");
291            if (converter == null)
292                throw new ArgumentNullException("converter");
293
294            foreach (TSource sourceItem in sourceCollection)
295                yield return converter(sourceItem);
296        }
297          */
298        /// <summary>
299        /// Creates a delegate that converts keys to values by used a dictionary to map values. Keys
300        /// that a not present in the dictionary are converted to the default value (zero or null).
301        /// </summary>
302        /// <remarks>This delegate can be used as a parameter in Convert or ConvertAll methods to convert
303        /// entire collections.</remarks>
304        /// <param name="dictionary">The dictionary used to perform the conversion.</param>
305        /// <returns>A delegate to a method that converts keys to values. </returns>
306        internal static Converter<TKey, TValue> GetDictionaryConverter<TKey, TValue>(IDictionary<TKey, TValue> dictionary)
307        {
308            return GetDictionaryConverter(dictionary, default(TValue));
309        }
310
311        /// <summary>
312        /// Creates a delegate that converts keys to values by used a dictionary to map values. Keys
313        /// that a not present in the dictionary are converted to a supplied default value.
314        /// </summary>
315        /// <remarks>This delegate can be used as a parameter in Convert or ConvertAll methods to convert
316        /// entire collections.</remarks>
317        /// <param name="dictionary">The dictionary used to perform the conversion.</param>
318        /// <param name="defaultValue">The result of the conversion for keys that are not present in the dictionary.</param>
319        /// <returns>A delegate to a method that converts keys to values. </returns>
320        /// <exception cref="ArgumentNullException"><paramref name="dictionary"/> is null.</exception>
321        internal static Converter<TKey, TValue> GetDictionaryConverter<TKey, TValue>(IDictionary<TKey, TValue> dictionary, TValue defaultValue)
322        {
323            if (dictionary == null)
324                throw new ArgumentNullException("dictionary");
325
326            return delegate(TKey key) {
327                TValue value;
328                if (dictionary.TryGetValue(key, out value))
329                    return value;
330                else
331                    return defaultValue;
332            };
333        }
334
335        /// <summary>
336        /// Performs the specified action on each item in a collection.
337        /// </summary>
338        /// <param name="collection">The collection to process.</param>
339        /// <param name="action">An Action delegate which is invoked for each item in <paramref name="collection"/>.</param>
340        internal static void ForEach<T>(IEnumerable<T> collection, Action<T> action)
341        {
342            if (collection == null)
343                throw new ArgumentNullException("collection");
344            if (action == null)
345                throw new ArgumentNullException("action");
346
347            foreach (T item in collection)
348                action(item);
349        }
350
351
352        #endregion Predicate operations
353
354
355
356        #region Sorting
357        /// <summary>
358        /// Sorts a list or array in place.
359        /// </summary>
360        /// <remarks><para>The Quicksort algorithms is used to sort the items. In virtually all cases,
361        /// this takes time O(N log N), where N is the number of items in the list.</para>
362        /// <para>Values are compared by using the IComparable&lt;T&gt;
363        /// interfaces implementation on the type T.</para>
364        /// <para>Although arrays cast to IList&lt;T&gt; are normally read-only, this method
365        /// will work correctly and modify an array passed as <paramref name="list"/>.</para></remarks>
366        /// <param name="list">The list or array to sort.</param>
367        public static void SortInPlace<T>(IList<T> list)
368            where T : IComparable<T>
369        {
370            SortInPlace<T>(list, Comparer<T>.Default);
371        }
372
373        /// <summary>
374        /// Sorts a list or array in place. A supplied IComparer&lt;T&gt; is used
375        /// to compare the items in the list.
376        /// </summary>
377        /// <remarks><para>The Quicksort algorithms is used to sort the items. In virtually all cases,
378        /// this takes time O(N log N), where N is the number of items in the list.</para>
379        /// <para>Although arrays cast to IList&lt;T&gt; are normally read-only, this method
380        /// will work correctly and modify an array passed as <paramref name="list"/>.</para></remarks>
381        /// <param name="list">The list or array to sort.</param>
382        /// <param name="comparer">The comparer instance used to compare items in the collection. Only
383        /// the Compare method is used.</param>
384        public static void SortInPlace<T>(IList<T> list, IComparer<T> comparer)
385        {
386            if(list == null)
387                throw new ArgumentNullException("Cannot sort a 'null' list.");
388            if(comparer == null)
389                throw new ArgumentNullException("The comparer is 'null'.");
390
391            // If we have an array, use the built-in array sort (faster than going through IList accessors
392            // with virtual calls).
393            if(list is T[])
394            {
395                Array.Sort((T[]) list, comparer);
396                return;
397            }
398
399            if(list.IsReadOnly)
400                throw new ArgumentException("The list is readonly.", "list");
401
402            // Instead of a recursive procedure, we use an explicit stack to hold
403            // ranges that we still need to sort.
404            int[] leftStack = new int[32], rightStack = new int[32];
405            int stackPtr = 0;
406
407            int l = 0;                       // the inclusive left edge of the current range we are sorting.
408            int r = list.Count - 1;    // the inclusive right edge of the current range we are sorting.
409            T partition;                   // The partition value.
410
411            // Loop until we have nothing left to sort. On each iteration, l and r contains the bounds
412            // of something to sort (unless r <= l), and leftStack/rightStack have a stack of unsorted
413            // pieces (unles stackPtr == 0).
414            for(; ; )
415            {
416                if(l == r - 1)
417                {
418                    // We have exactly 2 elements to sort. Compare them and swap if needed.
419                    T e1, e2;
420                    e1 = list[l];
421                    e2 = list[r];
422                    if(comparer.Compare(e1, e2) > 0)
423                    {
424                        list[r] = e1;
425                        list[l] = e2;
426                    }
427                    l = r;     // sort complete, find other work from the stack.
428                }
429                else if(l < r)
430                {
431                    // Sort the items in the inclusive range l .. r
432
433                    // Get the left, middle, and right-most elements and sort them, yielding e1=smallest, e2=median, e3=largest
434                    int m = l + (r - l) / 2;
435                    T e1 = list[l], e2 = list[m], e3 = list[r], temp;
436                    if(comparer.Compare(e1, e2) > 0)
437                    {
438                        temp = e1;
439                        e1 = e2;
440                        e2 = temp;
441                    }
442                    if(comparer.Compare(e1, e3) > 0)
443                    {
444                        temp = e3;
445                        e3 = e2;
446                        e2 = e1;
447                        e1 = temp;
448                    }
449                    else if(comparer.Compare(e2, e3) > 0)
450                    {
451                        temp = e2;
452                        e2 = e3;
453                        e3 = temp;
454                    }
455
456                    if(l == r - 2)
457                    {
458                        // We have exactly 3 elements to sort, and we've done that. Store back and we're done.
459                        list[l] = e1;
460                        list[m] = e2;
461                        list[r] = e3;
462                        l = r;  // sort complete, find other work from the stack.
463                    }
464                    else
465                    {
466                        // Put the smallest at the left, largest in the middle, and the median at the right (which is the partitioning value)
467                        list[l] = e1;
468                        list[m] = e3;
469                        list[r] = partition = e2;
470
471                        // Partition into three parts, items <= partition, items == partition, and items >= partition
472                        int i = l, j = r;
473                        T item_i, item_j;
474                        for(; ; )
475                        {
476                            do
477                            {
478                                ++i;
479                                item_i = list[i];
480                            } while(comparer.Compare(item_i, partition) < 0);
481
482                            do
483                            {
484                                --j;
485                                item_j = list[j];
486                            } while(comparer.Compare(item_j, partition) > 0);
487
488                            if(j < i)
489                                break;
490
491                            list[i] = item_j;
492                            list[j] = item_i; // swap items to continue the partition.
493                        }
494
495                        // Move the partition value into place.
496                        list[r] = item_i;
497                        list[i] = partition;
498                        ++i;
499
500                        // We have partitioned the list.
501                        //    Items in the inclusive range l .. j are <= partition.
502                        //    Items in the inclusive range i .. r are >= partition.
503                        //    Items in the inclusive range j+1 .. i - 1 are == partition (and in the correct final position).
504                        // We now need to sort l .. j and i .. r.
505                        // To do this, we stack one of the lists for later processing, and change l and r to the other list.
506                        // If we always stack the larger of the two sub-parts, the stack cannot get greater
507                        // than log2(Count) in size; i.e., a 32-element stack is enough for the maximum list size.
508                        if((j - l) > (r - i))
509                        {
510                            // The right partition is smaller. Stack the left, and get ready to sort the right.
511                            leftStack[stackPtr] = l;
512                            rightStack[stackPtr] = j;
513                            l = i;
514                        }
515                        else
516                        {
517                            // The left partition is smaller. Stack the right, and get ready to sort the left.
518                            leftStack[stackPtr] = i;
519                            rightStack[stackPtr] = r;
520                            r = j;
521                        }
522                        ++stackPtr;
523                    }
524                }
525                else if(stackPtr > 0)
526                {
527                    // We have a stacked sub-list to sort. Pop it off and sort it.
528                    --stackPtr;
529                    l = leftStack[stackPtr];
530                    r = rightStack[stackPtr];
531                }
532                else
533                {
534                    // We have nothing left to sort.
535                    break;
536                }
537            }
538        }
539
540     
541        #endregion
542
543    }
544}
Note: See TracBrowser for help on using the repository browser.