//******************************************************************************************************* // CollectionExtensions.cs - Gbtc // // Tennessee Valley Authority, 2009 // No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved. // // This software is made freely available under the TVA Open Source Agreement (see below). // Code in this file licensed to GSF under one or more contributor license agreements listed below. // // Code Modification History: // ----------------------------------------------------------------------------------------------------- // 02/23/2003 - J. Ritchie Carroll // Generated original version of source code. // 01/23/2005 - J. Ritchie Carroll // Migrated 2.0 version of source code from 1.1 source (GSF.Shared.Common). // 08/17/2007 - Darrell Zuercher // Edited code comments. // 09/11/2008 - J. Ritchie Carroll // Converted to C# extension functions. // 02/17/2009 - Josh L. Patterson // Edited Code Comments. // 02/20/2009 - J. Ritchie Carroll // Added predicate based IndexOf that extends IList. // 04/02/2009 - J. Ritchie Carroll // Added seed based scramble and unscramble IList extensions. // 06/05/2009 - Pinal C. Patel // Added generic AddRange() extension method for IList. // 06/09/2009 - Pinal C. Patel // Added generic GetRange() extension method for IList. // 08/05/2009 - Josh L. Patterson // Update comments. // 09/14/2009 - Stephen C. Wills // Added new header and license agreement. // 11/17/2009 - Pinal C. Patel // Added generic UpdateRange() extension method for IList. // 03/31/2009 - J. Ritchie Carroll // Added Majority() and Minority() extension methods to IEnumerable. // 03/18/2011 - J. Ritchie Carroll // Added dictionary Merge() extensions method for IDictionary and Any/All extensions for BitArray. // 03/22/2011 - J. Ritchie Carroll // Modified array copy extension to handle zero length (i.e., empty) source arrays. // 10/17/2011 - J. Ritchie Carroll // Added the ability to specify a default value for Majority and Minority when none exists. // //******************************************************************************************************* #region [ TVA Open Source Agreement ] /* THIS OPEN SOURCE AGREEMENT ("AGREEMENT") DEFINES THE RIGHTS OF USE,REPRODUCTION, DISTRIBUTION, MODIFICATION AND REDISTRIBUTION OF CERTAIN COMPUTER SOFTWARE ORIGINALLY RELEASED BY THE TENNESSEE VALLEY AUTHORITY, A CORPORATE AGENCY AND INSTRUMENTALITY OF THE UNITED STATES GOVERNMENT ("GOVERNMENT AGENCY"). GOVERNMENT AGENCY IS AN INTENDED THIRD-PARTY BENEFICIARY OF ALL SUBSEQUENT DISTRIBUTIONS OR REDISTRIBUTIONS OF THE SUBJECT SOFTWARE. ANYONE WHO USES, REPRODUCES, DISTRIBUTES, MODIFIES OR REDISTRIBUTES THE SUBJECT SOFTWARE, AS DEFINED HEREIN, OR ANY PART THEREOF, IS, BY THAT ACTION, ACCEPTING IN FULL THE RESPONSIBILITIES AND OBLIGATIONS CONTAINED IN THIS AGREEMENT. Original Software Designation: openPDC Original Software Title: The GSF Open Source Phasor Data Concentrator User Registration Requested. Please Visit https://naspi.tva.com/Registration/ Point of Contact for Original Software: J. Ritchie Carroll 1. DEFINITIONS A. "Contributor" means Government Agency, as the developer of the Original Software, and any entity that makes a Modification. B. "Covered Patents" mean patent claims licensable by a Contributor that are necessarily infringed by the use or sale of its Modification alone or when combined with the Subject Software. C. "Display" means the showing of a copy of the Subject Software, either directly or by means of an image, or any other device. D. "Distribution" means conveyance or transfer of the Subject Software, regardless of means, to another. E. "Larger Work" means computer software that combines Subject Software, or portions thereof, with software separate from the Subject Software that is not governed by the terms of this Agreement. F. "Modification" means any alteration of, including addition to or deletion from, the substance or structure of either the Original Software or Subject Software, and includes derivative works, as that term is defined in the Copyright Statute, 17 USC § 101. However, the act of including Subject Software as part of a Larger Work does not in and of itself constitute a Modification. G. "Original Software" means the computer software first released under this Agreement by Government Agency entitled openPDC, including source code, object code and accompanying documentation, if any. H. "Recipient" means anyone who acquires the Subject Software under this Agreement, including all Contributors. I. "Redistribution" means Distribution of the Subject Software after a Modification has been made. J. "Reproduction" means the making of a counterpart, image or copy of the Subject Software. K. "Sale" means the exchange of the Subject Software for money or equivalent value. L. "Subject Software" means the Original Software, Modifications, or any respective parts thereof. M. "Use" means the application or employment of the Subject Software for any purpose. 2. GRANT OF RIGHTS A. Under Non-Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor, with respect to its own contribution to the Subject Software, hereby grants to each Recipient a non-exclusive, world-wide, royalty-free license to engage in the following activities pertaining to the Subject Software: 1. Use 2. Distribution 3. Reproduction 4. Modification 5. Redistribution 6. Display B. Under Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor, with respect to its own contribution to the Subject Software, hereby grants to each Recipient under Covered Patents a non-exclusive, world-wide, royalty-free license to engage in the following activities pertaining to the Subject Software: 1. Use 2. Distribution 3. Reproduction 4. Sale 5. Offer for Sale C. The rights granted under Paragraph B. also apply to the combination of a Contributor's Modification and the Subject Software if, at the time the Modification is added by the Contributor, the addition of such Modification causes the combination to be covered by the Covered Patents. It does not apply to any other combinations that include a Modification. D. The rights granted in Paragraphs A. and B. allow the Recipient to sublicense those same rights. Such sublicense must be under the same terms and conditions of this Agreement. 3. OBLIGATIONS OF RECIPIENT A. Distribution or Redistribution of the Subject Software must be made under this Agreement except for additions covered under paragraph 3H. 1. Whenever a Recipient distributes or redistributes the Subject Software, a copy of this Agreement must be included with each copy of the Subject Software; and 2. If Recipient distributes or redistributes the Subject Software in any form other than source code, Recipient must also make the source code freely available, and must provide with each copy of the Subject Software information on how to obtain the source code in a reasonable manner on or through a medium customarily used for software exchange. B. Each Recipient must ensure that the following copyright notice appears prominently in the Subject Software: No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved. C. Each Contributor must characterize its alteration of the Subject Software as a Modification and must identify itself as the originator of its Modification in a manner that reasonably allows subsequent Recipients to identify the originator of the Modification. In fulfillment of these requirements, Contributor must include a file (e.g., a change log file) that describes the alterations made and the date of the alterations, identifies Contributor as originator of the alterations, and consents to characterization of the alterations as a Modification, for example, by including a statement that the Modification is derived, directly or indirectly, from Original Software provided by Government Agency. Once consent is granted, it may not thereafter be revoked. D. A Contributor may add its own copyright notice to the Subject Software. Once a copyright notice has been added to the Subject Software, a Recipient may not remove it without the express permission of the Contributor who added the notice. E. A Recipient may not make any representation in the Subject Software or in any promotional, advertising or other material that may be construed as an endorsement by Government Agency or by any prior Recipient of any product or service provided by Recipient, or that may seek to obtain commercial advantage by the fact of Government Agency's or a prior Recipient's participation in this Agreement. F. In an effort to track usage and maintain accurate records of the Subject Software, each Recipient, upon receipt of the Subject Software, is requested to register with Government Agency by visiting the following website: https://naspi.tva.com/Registration/. Recipient's name and personal information shall be used for statistical purposes only. Once a Recipient makes a Modification available, it is requested that the Recipient inform Government Agency at the web site provided above how to access the Modification. G. Each Contributor represents that that its Modification does not violate any existing agreements, regulations, statutes or rules, and further that Contributor has sufficient rights to grant the rights conveyed by this Agreement. H. A Recipient may choose to offer, and to charge a fee for, warranty, support, indemnity and/or liability obligations to one or more other Recipients of the Subject Software. A Recipient may do so, however, only on its own behalf and not on behalf of Government Agency or any other Recipient. Such a Recipient must make it absolutely clear that any such warranty, support, indemnity and/or liability obligation is offered by that Recipient alone. Further, such Recipient agrees to indemnify Government Agency and every other Recipient for any liability incurred by them as a result of warranty, support, indemnity and/or liability offered by such Recipient. I. A Recipient may create a Larger Work by combining Subject Software with separate software not governed by the terms of this agreement and distribute the Larger Work as a single product. In such case, the Recipient must make sure Subject Software, or portions thereof, included in the Larger Work is subject to this Agreement. J. Notwithstanding any provisions contained herein, Recipient is hereby put on notice that export of any goods or technical data from the United States may require some form of export license from the U.S. Government. Failure to obtain necessary export licenses may result in criminal liability under U.S. laws. Government Agency neither represents that a license shall not be required nor that, if required, it shall be issued. Nothing granted herein provides any such export license. 4. DISCLAIMER OF WARRANTIES AND LIABILITIES; WAIVER AND INDEMNIFICATION A. No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." B. Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST GOVERNMENT AGENCY, ITS AGENTS, EMPLOYEES, CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS GOVERNMENT AGENCY, ITS AGENTS, EMPLOYEES, CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. THE FOREGOING RELEASE AND INDEMNIFICATION SHALL APPLY EVEN IF THE LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARE CAUSED, OCCASIONED, OR CONTRIBUTED TO BY THE NEGLIGENCE, SOLE OR CONCURRENT, OF GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT. RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS AGREEMENT. 5. GENERAL TERMS A. Termination: This Agreement and the rights granted hereunder will terminate automatically if a Recipient fails to comply with these terms and conditions, and fails to cure such noncompliance within thirty (30) days of becoming aware of such noncompliance. Upon termination, a Recipient agrees to immediately cease use and distribution of the Subject Software. All sublicenses to the Subject Software properly granted by the breaching Recipient shall survive any such termination of this Agreement. B. Severability: If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement. C. Applicable Law: This Agreement shall be subject to United States federal law only for all purposes, including, but not limited to, determining the validity of this Agreement, the meaning of its provisions and the rights, obligations and remedies of the parties. D. Entire Understanding: This Agreement constitutes the entire understanding and agreement of the parties relating to release of the Subject Software and may not be superseded, modified or amended except by further written agreement duly executed by the parties. E. Binding Authority: By accepting and using the Subject Software under this Agreement, a Recipient affirms its authority to bind the Recipient to all terms and conditions of this Agreement and that Recipient hereby agrees to all terms and conditions herein. F. Point of Contact: Any Recipient contact with Government Agency is to be directed to the designated representative as follows: J. Ritchie Carroll . */ #endregion #region [ Contributor License Agreements ] //****************************************************************************************************** // // Copyright © 2011, Grid Protection Alliance. All Rights Reserved. // // The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/eclipse-1.0.php // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // //****************************************************************************************************** #endregion using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; namespace GSF.Collections { /// /// Defines extension functions related to manipulation of arrays and collections. /// public static class CollectionExtensions { /// /// Merges elements of multiple dictionaries into a single dictionary with no duplicate key values overwritten. /// /// Type of to merge. /// Type of keys. /// Type of values. /// Source dictionary to merge with another dictionary. /// Other dictionaries to merge with source dictionary. /// /// A merged collection of all unique dictionary elements, all merged left to the source with no duplicate /// key values overwritten (i.e., first encounted key value pair is the one that remains in the returned merged dictionary). /// public static T Merge(this T source, params IDictionary[] others) where T : IDictionary, new() { return source.Merge(false, others); } /// /// Merges elements of multiple dictionaries into a single dictionary. /// /// Type of to merge. /// Type of keys. /// Type of values. /// Source dictionary to merge with another dictionary. /// Set to true to overwrite duplicate key values as they are encountered. /// Other dictionaries to merge with source dictionary. /// A merged collection of all unique dictionary elements, all merged left to the source. public static T Merge(this T source, bool overwriteExisting, params IDictionary[] others) where T : IDictionary, new() { T mergedDictionary = new T(); List> allDictionaries = new List>(); allDictionaries.Add(source); allDictionaries.AddRange(others); foreach (IDictionary dictionary in allDictionaries) { foreach (KeyValuePair kvPair in dictionary) { if (overwriteExisting) { mergedDictionary[kvPair.Key] = kvPair.Value; } else { if (!mergedDictionary.ContainsKey(kvPair.Key)) mergedDictionary.Add(kvPair); } } } return mergedDictionary; } /// /// Returns true if any item in is equal to . /// /// Source . /// value to test for. /// true if any item in is equal to . public static bool Any(this BitArray source, bool value) { return source.Cast().Any(item => item == value); } /// /// Returns true if all items in are equal to . /// /// Source . /// value to test for. /// true if all items in are equal to . public static bool All(this BitArray source, bool value) { return source.Cast().All(item => item == value); } /// /// Returns the majority value in the collection, or default type value if no item represents the majority. /// /// of elements in the . /// An enumeration over which to find the majority element. /// The majority value in the collection. public static T Majority(this IEnumerable source) { return source.Majority(default(T)); } /// /// Returns the majority value in the collection, or if no item represents the majority. /// /// of elements in the . /// An enumeration over which to find the majority element. /// Default value to return if no item represents the majority. /// The majority value in the collection. public static T Majority(this IEnumerable source, T defaultValue) { T majority = defaultValue; if ((object)source != null && source.Count() > 1) { Dictionary itemCounts = new Dictionary(); int count; // Count each number of items in the list foreach (T item in source) { if (itemCounts.TryGetValue(item, out count)) { count++; itemCounts[item] = count; } else itemCounts.Add(item, 1); } // Find the largest number of items in the list KeyValuePair maxItem = itemCounts.Max((a, b) => (a.Value < b.Value ? -1 : (a.Value > b.Value ? 1 : 0))); // If item with largest count has a plural majority, then it is the majority item if (maxItem.Value > 1) majority = maxItem.Key; } else majority = source.FirstOrDefault(); return majority; } /// /// Returns the minority value in the collection, or default type value if no item represents the minority. /// /// of elements in the . /// An enumeration over which to find the minority element. /// The minority value in the collection. public static T Minority(this IEnumerable source) { return source.Minority(default(T)); } /// /// Returns the minority value in the collection, or if no item represents the minority. /// /// of elements in the . /// An enumeration over which to find the minority element. /// Default value to return if no item represents the minority. /// The minority value in the collection. public static T Minority(this IEnumerable source, T defaultValue) { T minority = defaultValue; if ((object)source != null && source.Count() > 1) { Dictionary itemCounts = new Dictionary(); int count; // Count each number of items in the list foreach (T item in source) { if (itemCounts.TryGetValue(item, out count)) { count++; itemCounts[item] = count; } else itemCounts.Add(item, 1); } // Find the smallest number of items in the list KeyValuePair minItem = itemCounts.Min((a, b) => (a.Value < b.Value ? -1 : (a.Value > b.Value ? 1 : 0))); minority = minItem.Key; } else minority = source.FirstOrDefault(); return minority; } /// /// Adds the specified to the . /// /// of elements in the . /// The collection to which the are to be added. /// The elements to be added to the . public static void AddRange(this IList collection, IEnumerable items) { foreach (T item in items) { collection.Add(item); } } /// /// Updates starting at the with the specified . /// /// of elements in the . /// The collection whose elements are to be updated with the specified . /// The zero-based index in the at which elements are to be updated. /// The elements that will replace the elements starting at the . /// The specified is present in the . public static void UpdateRange(this IList collection, int index, IEnumerable items) { foreach (T item in items) { collection[index++] = item; } } /// /// Returns elements in the specified range from the . /// /// of elements in the . /// The collection from which elements are to be retrieved. /// The 0-based index position in the from which elements are to be retrieved. /// The number of elements to be retrieved from the starting at the . /// An object. public static IList GetRange(this IList collection, int index, int count) { List result = new List(); for (int i = index; i < index + count; i++) { result.Add(collection[i]); } return result; } /// /// Returns the index of the first element of the sequence that satisfies a condition or -1 if no such element is found. /// /// A to find an index in. /// A function to test each element for a condition. /// Index of the first element in that matches the specified ; otherwise, -1. /// The type of the elements of . public static int IndexOf(this IList source, Func predicate) { for (int index = 0; index < source.Count; index++) { if (predicate(source[index])) return index; } return -1; } /// /// Returns a copy of the . /// /// of the to be copied. /// The source whose elements are to be copied. /// The source array index from where the elements are to be copied. /// The number of elements to be copied starting from the startIndex. /// An of elements copied from the specified portion of the source . /// /// Returned will be extended as needed to make it the specified , but /// it will never be less than the source length - . /// /// /// is outside the range of valid indexes for the source -or- /// is less than 0. /// public static T[] Copy(this T[] source, int startIndex, int length) { if (startIndex < 0 || length < 0) throw new ArgumentOutOfRangeException(startIndex < 0 ? "startIndex" : "length", "Cannot be negative"); if (source.Length == 0) return new T[length]; if (startIndex >= source.Length) throw new ArgumentOutOfRangeException("startIndex", "Not a valid index into source buffer"); // Create a new array that will be returned with the specified array elements. T[] copyOfSource = new T[source.Length - startIndex < length ? source.Length - startIndex : length]; Array.Copy(source, startIndex, copyOfSource, 0, copyOfSource.Length); return copyOfSource; } /// Returns the smallest item from the enumeration. /// The generic type used. /// An enumeration that is compared against. /// A delegate that takes two generic types to compare, and returns an integer based on the comparison. /// Returns a generic type. public static TSource Min(this IEnumerable source, Func comparer) { TSource minItem = default(TSource); IEnumerator enumerator = source.GetEnumerator(); if (enumerator.MoveNext()) { minItem = enumerator.Current; while (enumerator.MoveNext()) { if (comparer(enumerator.Current, minItem) < 0) minItem = enumerator.Current; } } return minItem; } /// Returns the smallest item from the enumeration. /// The generic type used. /// An enumeration that is compared against. /// A comparer object. /// Returns a generic type. public static TSource Min(this IEnumerable source, IComparer comparer) { return source.Min(comparer.Compare); } /// Returns the largest item from the enumeration. /// The generic type used. /// An enumeration that is compared against. /// A delegate that takes two generic types to compare, and returns an integer based on the comparison. /// Returns a generic type. public static TSource Max(this IEnumerable source, Func comparer) { TSource maxItem = default(TSource); IEnumerator enumerator = source.GetEnumerator(); if (enumerator.MoveNext()) { maxItem = enumerator.Current; while (enumerator.MoveNext()) { if (comparer(enumerator.Current, maxItem) > 0) maxItem = enumerator.Current; } } return maxItem; } /// Returns the largest item from the enumeration. /// The generic type used. /// An enumeration that is compared against. /// A comparer object. /// Returns a generic type. public static TSource Max(this IEnumerable source, IComparer comparer) { return source.Max(comparer.Compare); } /// Converts an enumeration to a string, using the default delimeter ("|") that can later be /// converted back to a list using LoadDelimitedString. /// The generic type used. /// The source object to be converted into a delimited string. /// Returns a that is result of combining all elements in the list delimited by the '|' character. public static string ToDelimitedString(this IEnumerable source) { return source.ToDelimitedString('|'); } /// Converts an enumeration to a string that can later be converted back to a list using /// LoadDelimitedString. /// The generic type used. /// The source object to be converted into a delimited string. /// The delimiting character used. /// Returns a that is result of combining all elements in the list delimited by . public static string ToDelimitedString(this IEnumerable source, char delimiter) { return ToDelimitedString(source, delimiter); } /// Converts an enumeration to a string that can later be converted back to a list using /// LoadDelimitedString. /// The generic type used. /// The source object to be converted into a delimited string. /// The delimiting used. /// Returns a that is result of combining all elements in the list delimited by . public static string ToDelimitedString(this IEnumerable source, string delimiter) { return ToDelimitedString(source, delimiter); } /// Converts an enumeration to a string that can later be converted back to a list using /// LoadDelimitedString. /// The generic enumeration type used. /// The generic delimiter type used. /// The source object to be converted into a delimited string. /// The delimeter of type TDelimiter used. /// Returns a that is result of combining all elements in the list delimited by . private static string ToDelimitedString(IEnumerable source, TDelimiter delimiter) { if (Common.IsReference(delimiter) && (object)delimiter == null) throw new ArgumentNullException("delimiter", "delimiter cannot be null"); StringBuilder delimetedString = new StringBuilder(); foreach (TSource item in source) { if (delimetedString.Length > 0) delimetedString.Append(delimiter); delimetedString.Append(item.ToString()); } return delimetedString.ToString(); } /// Appends items parsed from delimited string, created with ToDelimitedString, using the default /// delimeter ("|") into the given list. /// Items that are converted are added to list. The list is not cleared in advance. /// The generic type used. /// The list we are adding items to. /// The delimited string to parse for items. /// Delegate that takes one parameter and converts from string to type TSource. public static void LoadDelimitedString(this IList destination, string delimitedString, Func convertFromString) { destination.LoadDelimitedString(delimitedString, '|', convertFromString); } /// Appends items parsed from delimited string, created with ToDelimitedString, into the given list. /// Items that are converted are added to list. The list is not cleared in advance. /// The generic type used. /// The list we are adding items to. /// The delimited string to parse for items. /// The value to look for in the as the delimiter. /// Delegate that takes one parameter and converts from string to type TSource. public static void LoadDelimitedString(this IList destination, string delimitedString, char delimeter, Func convertFromString) { if ((object)delimitedString == null) throw new ArgumentNullException("delimitedString", "delimitedString cannot be null"); if (destination.IsReadOnly) throw new ArgumentException("Cannot add items to a read only list"); foreach (string item in delimitedString.Split(delimeter)) { destination.Add(convertFromString(item.Trim())); } } /// Appends items parsed from delimited string, created with ToDelimitedString, into the given list. /// Items that are converted are added to list. The list is not cleared in advance. /// The generic type used. /// The list we are adding items to. /// The delimited string to parse for items. /// An array of delimiters to look for in the as the delimiter. /// Delegate that takes a and converts to type TSource. public static void LoadDelimitedString(this IList destination, string delimitedString, string[] delimiters, Func convertFromString) { if ((object)delimiters == null) throw new ArgumentNullException("delimiters", "delimiters cannot be null"); if ((object)delimitedString == null) throw new ArgumentNullException("delimitedString", "delimitedString cannot be null"); if (destination.IsReadOnly) throw new ArgumentException("Cannot add items to a read only list"); foreach (string item in delimitedString.Split(delimiters, StringSplitOptions.None)) { destination.Add(convertFromString(item.Trim())); } } // /// // /// Rearranges all the elements in the list into a random order. // /// // /// The generic type of the list. // /// The input list of generic types to scramble. // /// This function uses a cryptographically strong random number generator to perform the scramble. // public static void Scramble(this IList source) // { // if (source.IsReadOnly) // throw new ArgumentException("Cannot modify items in a read only list"); // // int x, y; // TSource currentItem; // // // Mixes up the data in random order. // for (x = 0; x < source.Count; x++) // { // // Calls random function from GSF namespace. // y = GSF.Security.Cryptography.Random.Int32Between(0, source.Count - 1); // // if (x != y) // { // // Swaps items // currentItem = source[x]; // source[x] = source[y]; // source[y] = currentItem; // } // } // } /// /// Rearranges all the elements in the list into a repeatable pseudo-random order. /// /// The input list of generic types to scramble. /// A number used to calculate a starting value for the pseudo-random number sequence. /// The generic type of the list. /// This function uses the generator to perform the scramble using a sequence that is repeatable. public static void Scramble(this IList source, int seed) { if (source.IsReadOnly) throw new ArgumentException("Cannot modify items in a read only list"); Random random = new Random(seed); int x, y, count = source.Count; TSource currentItem; // Mixes up the data in random order. for (x = 0; x < count; x++) { // Calls random function from System namespace. y = random.Next(count); if (x != y) { // Swaps items currentItem = source[x]; source[x] = source[y]; source[y] = currentItem; } } } /// /// Rearranges all the elements in the list previously scrambled with back into their original order. /// /// The input list of generic types to unscramble. /// The same number used in call to scramble original list. /// The generic type of the list. /// This function uses the generator to perform the unscramble using a sequence that is repeatable. public static void Unscramble(this IList source, int seed) { if (source.IsReadOnly) throw new ArgumentException("Cannot modify items in a read only list"); Random random = new Random(seed); List sequence = new List(); int x, y, count = source.Count; TSource currentItem; // Generate original scramble sequence. for (x = 0; x < count; x++) { // Calls random function from System namespace. sequence.Add(random.Next(count)); } // Unmix the data order (traverse same sequence in reverse order). for (x = count - 1; x >= 0; x--) { y = sequence[x]; if (x != y) { // Swaps items currentItem = source[x]; source[x] = source[y]; source[y] = currentItem; } } } /// Compares two arrays. /// The first type array to compare to. /// The second type array to compare against. /// An which returns 0 if they are equal, 1 if is larger, or -1 if is larger. /// The generic type of the list. public static int CompareTo(this TSource[] array1, TSource[] array2) { return CompareTo(array1, array2, Comparer.Default); } /// Compares two arrays. /// The first to compare to. /// The second to compare against. /// An interface that exposes a method to compare the two arrays. /// An which returns 0 if they are equal, 1 if is larger, or -1 if is larger. /// This is a default comparer to make arrays comparable. public static int CompareTo(this Array array1, Array array2, IComparer comparer) { if ((object)comparer == null) throw new ArgumentNullException("comparer"); if ((object)array1 == null && (object)array2 == null) { return 0; } else if ((object)array1 == null) { return -1; } else if ((object)array2 == null) { return 1; } else { if (array1.Rank == 1 && array2.Rank == 1) { if (array1.Length == array2.Length) { int comparison = 0; for (int x = 0; x < array1.Length; x++) { comparison = comparer.Compare(array1.GetValue(x), array2.GetValue(x)); if (comparison != 0) break; } return comparison; } else { // For arrays that do not have the same number of elements, the array with most elements // is assumed to be larger. return array1.Length.CompareTo(array2.Length); } } else { throw new ArgumentException("Cannot compare multidimensional arrays"); } } } } }