1270 lines · 64.6 KB · C#
RawDownload
//******************************************************************************************************//  CollectionExtensions.cs - Gbtc////  Copyright © 2012, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), 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/MIT////  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.////  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<T>.//  04/02/2009 - J. Ritchie Carroll//       Added seed based scramble and unscramble IList<T> extensions.//  06/05/2009 - Pinal C. Patel//       Added generic AddRange() extension method for IList<T>.//  06/09/2009 - Pinal C. Patel//       Added generic GetRange() extension method for IList<T>.//  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<T>.//  03/31/2009 - J. Ritchie Carroll//       Added Majority() and Minority() extension methods to IEnumerable<T>.//  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.//  12/13/2012 - Starlynn Danyelle Gilliam//       Modified Header.//  03/13/2016 - J. Ritchie Carroll//       Added ToPagedList extension for enumerations.////****************************************************************************************************** using System;using System.Collections;using System.Collections.Generic;using System.Collections.Specialized;using System.Linq;using System.Text;using System.Threading.Tasks;using Random = GSF.Security.Cryptography.Random; namespace GSF.Collections{    /// <summary>    /// Defines extension functions related to manipulation of arrays and collections.    /// </summary>    public static class CollectionExtensions    {        /// <summary>        /// Gets a <see cref="PagedList{T}"/> to paginate <paramref name="source"/> enumeration for        /// a given <paramref name="page"/> and specified <paramref name="pageSize"/>.        /// </summary>        /// <typeparam name="T">Type of <see cref="IEnumerable{T}"/> to paginate.</typeparam>        /// <param name="source">Source enumeration to paginate.</param>        /// <param name="page">Page number (1-based).</param>        /// <param name="pageSize">Page size.</param>        /// <param name="count">Total records in source if known.</param>        /// <returns>Set of items on a given <paramref name="page"/> for specified <paramref name="pageSize"/>.</returns>        /// <remarks>        /// If count is known or can be calculated early, specify the value in the        /// <paramref name="count"/> parameter as an optimization to prevent a full        /// enumeration on <paramref name="source"/> to get a count.        /// </remarks>        public static PagedList<T> ToPagedList<T>(this IEnumerable<T> source, int page, int pageSize, int count = -1)        {            return new PagedList<T>(source, page, pageSize, count);        }         /// <summary>        /// Merges elements of multiple dictionaries into a single dictionary with no duplicate key values overwritten.        /// </summary>        /// <typeparam name="T">Type of <see cref="IDictionary{TKey, TValue}"/> to merge.</typeparam>        /// <typeparam name="TKey">Type of <see cref="IDictionary{TKey, TValue}"/> keys.</typeparam>        /// <typeparam name="TValue">Type of <see cref="IDictionary{TKey, TValue}"/> values.</typeparam>        /// <param name="source">Source dictionary to merge with another dictionary.</param>        /// <param name="others">Other dictionaries to merge with source dictionary.</param>        /// <returns>        /// A merged collection of all unique dictionary elements, all <paramref name="others"/> merged left to the source with no duplicate        /// key values overwritten (i.e., first encountered key value pair is the one that remains in the returned merged dictionary).        /// </returns>        public static T Merge<T, TKey, TValue>(this T source, params IDictionary<TKey, TValue>[] others) where T : IDictionary<TKey, TValue>, new()        {            return source.Merge(false, others);        }         /// <summary>        /// Merges elements of multiple dictionaries into a single dictionary.        /// </summary>        /// <typeparam name="T">Type of <see cref="IDictionary{TKey, TValue}"/> to merge.</typeparam>        /// <typeparam name="TKey">Type of <see cref="IDictionary{TKey, TValue}"/> keys.</typeparam>        /// <typeparam name="TValue">Type of <see cref="IDictionary{TKey, TValue}"/> values.</typeparam>        /// <param name="source">Source dictionary to merge with another dictionary.</param>        /// <param name="overwriteExisting">Set to <c>true</c> to overwrite duplicate key values as they are encountered.</param>        /// <param name="others">Other dictionaries to merge with source dictionary.</param>        /// <returns>A merged collection of all unique dictionary elements, all <paramref name="others"/> merged left to the source.</returns>        public static T Merge<T, TKey, TValue>(this T source, bool overwriteExisting, params IDictionary<TKey, TValue>[] others) where T : IDictionary<TKey, TValue>, new()        {            T mergedDictionary = new T();            List<IDictionary<TKey, TValue>> allDictionaries = new List<IDictionary<TKey, TValue>>();             allDictionaries.Add(source);            allDictionaries.AddRange(others);             foreach (IDictionary<TKey, TValue> dictionary in allDictionaries)            {                foreach (KeyValuePair<TKey, TValue> kvPair in dictionary)                {                    if (overwriteExisting)                    {                        mergedDictionary[kvPair.Key] = kvPair.Value;                    }                    else                    {                        if (!mergedDictionary.ContainsKey(kvPair.Key))                            mergedDictionary.Add(kvPair);                    }                }            }             return mergedDictionary;        }         /// <summary>        /// Attempts to get the value for the given key and returns the default value instead if the key does not exist in the <see cref="IDictionary{TKey, TValue}"/>.        /// </summary>        /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>        /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>        /// <param name="dictionary">The dictionary to check for the given key.</param>        /// <param name="key">The key to be checked for the existence of a value.</param>        /// <returns>The value of the key in the dictionary or the default value if no such value exists.</returns>        public static TValue GetOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)        {            return dictionary.GetOrDefault(key, k => default(TValue));        }         /// <summary>        /// Attempts to get the value for the given key and returns the default value instead if the key does not exist in the <see cref="IDictionary{TKey, TValue}"/>.        /// </summary>        /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>        /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>        /// <param name="dictionary">The dictionary to check for the given key.</param>        /// <param name="key">The key to be checked for the existence of a value.</param>        /// <param name="defaultValueFactory">The function used to generate the default value if no value exists for the given key.</param>        /// <returns>The value of the key in the dictionary or the default value if no such value exists.</returns>        public static TValue GetOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> defaultValueFactory)        {            TValue value;             if (!dictionary.TryGetValue(key, out value))                value = defaultValueFactory(key);             return value;        }         /// <summary>        /// Adds a key/value pair to the <see cref="IDictionary{TKey, TValue}"/> if the key does not already exist.        /// </summary>        /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>        /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>        /// <param name="dictionary">The dictionary to add the key/value pair to if the key does not already exist.</param>        /// <param name="key">The key to be added to the dictionary if it does not already exist.</param>        /// <param name="valueFactory">The function used to generate a value for the key.</param>        /// <returns>The value of the key in the dictionary.</returns>        public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> valueFactory)        {            TValue value;             if (!dictionary.TryGetValue(key, out value))            {                value = valueFactory(key);                dictionary.Add(key, value);            }             return value;        }         /// <summary>        /// Adds a key/value pair to the <see cref="IDictionary{TKey, TValue}"/> if the key does not already exist.        /// </summary>        /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>        /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>        /// <param name="dictionary">The dictionary to add the key/value pair to if the key does not already exist.</param>        /// <param name="key">The key to be added to the dictionary if it does not already exist.</param>        /// <param name="value">The value to assign to the key if the key does not already exist.</param>        /// <returns>The value of the key in the dictionary.</returns>        public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue value)        {            TValue tryGetValue;             if (!dictionary.TryGetValue(key, out tryGetValue))            {                tryGetValue = value;                dictionary.Add(key, tryGetValue);            }             return tryGetValue;        }         /// <summary>        /// Adds a key/value pair to the <see cref="IDictionary{TKey, TValue}"/> if the key does not already exist,        /// or updates a key/value pair in the <see cref="IDictionary{TKey, TValue}"/> if the key already exists.        /// </summary>        /// <param name="dictionary">The dictionary to add the key/value pair to if the key does not already exist.</param>        /// <param name="key">The key to be added or whose value should be updated</param>        /// <param name="addValueFactory">The function used to generate a value for an absent key</param>        /// <param name="updateValueFactory">The function used to generate a new value for an existing key based on the key's existing value</param>        /// <returns>The new value for the key. This will be either be the result of addValueFactory (if the key was absent) or the result of updateValueFactory (if the key was present).</returns>        public static TValue AddOrUpdate<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory)        {            TValue value;             if (dictionary.TryGetValue(key, out value))                value = updateValueFactory(key, value);            else                value = addValueFactory(key);             dictionary[key] = value;             return value;        }         /// <summary>        /// Adds a key/value pair to the <see cref="IDictionary{TKey, TValue}"/> if the key does not already exist,        /// or updates a key/value pair in the <see cref="IDictionary{TKey, TValue}"/> if the key already exists.        /// </summary>        /// <param name="dictionary">The dictionary to add the key/value pair to if the key does not already exist.</param>        /// <param name="key">The key to be added or whose value should be updated</param>        /// <param name="addValue">The value to be added for an absent key</param>        /// <param name="updateValueFactory">The function used to generate a new value for an existing key based on the key's existing value</param>        /// <returns>The new value for the key. This will be either be the result of addValueFactory (if the key was absent) or the result of updateValueFactory (if the key was present).</returns>        public static TValue AddOrUpdate<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory)        {            TValue value;             if (dictionary.TryGetValue(key, out value))                value = updateValueFactory(key, value);            else                value = addValue;             dictionary[key] = value;             return value;        }         /// <summary>        /// Adds a key/value pair to the <see cref="IDictionary{TKey, TValue}"/> if the key does not already exist,        /// or updates a key/value pair in the <see cref="IDictionary{TKey, TValue}"/> if the key already exists.        /// </summary>        /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>        /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>        /// <param name="dictionary">The dictionary to add the key/value pair to if the key does not already exist.</param>        /// <param name="key">The key to be added or updated.</param>        /// <param name="valueFactory">The function used to generate a value for the key.</param>        /// <returns>The value of the key in the dictionary after updating.</returns>        public static TValue AddOrUpdate<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> valueFactory)        {            TValue value = valueFactory(key);            dictionary[key] = value;            return value;        }         /// <summary>        /// Adds a key/value pair to the <see cref="IDictionary{TKey, TValue}"/> if the key does not already exist,        /// or updates a key/value pair in the <see cref="IDictionary{TKey, TValue}"/> if the key already exists.        /// </summary>        /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>        /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>        /// <param name="dictionary">The dictionary to add the key/value pair to if the key does not already exist.</param>        /// <param name="key">The key to be added or updated.</param>        /// <param name="value">The value to be assigned to the key.</param>        /// <returns>The value of the key in the dictionary after updating.</returns>        public static TValue AddOrUpdate<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue value)        {            dictionary[key] = value;            return value;        }         /// <summary>        /// Converts a name/value collection to a dictionary.        /// </summary>        /// <param name="collection">Name/value collection.</param>        /// <returns>Dictionary converted from a name/value collection.</returns>        public static Dictionary<string, string> ToDictionary(this NameValueCollection collection)        {            return collection.AllKeys.ToDictionary(key => key, key => collection[key]);        }         /// <summary>        /// Returns <c>true</c> if any item in <see cref="BitArray"/> is equal to <paramref name="value"/>.        /// </summary>        /// <param name="source">Source <see cref="BitArray"/>.</param>        /// <param name="value"><see cref="bool"/> value to test for.</param>        /// <returns><c>true</c> if any item in <see cref="BitArray"/> is equal to <paramref name="value"/>.</returns>        public static bool Any(this BitArray source, bool value)        {            return source.Cast<bool>().Any(item => item == value);        }         /// <summary>        /// Returns <c>true</c> if all items in <see cref="BitArray"/> are equal to <paramref name="value"/>.        /// </summary>        /// <param name="source">Source <see cref="BitArray"/>.</param>        /// <param name="value"><see cref="bool"/> value to test for.</param>        /// <returns><c>true</c> if all items in <see cref="BitArray"/> are equal to <paramref name="value"/>.</returns>        public static bool All(this BitArray source, bool value)        {            return source.Cast<bool>().All(item => item == value);        }         /// <summary>        /// Determines whether all elements of a sequence satisfy a condition with each item being tested in parallel.        /// </summary>        /// <param name="source">An <see cref="IEnumerable{TSource}" /> that contains the elements to apply the predicate to.</param>        /// <param name="predicate">A function to test each element for a condition.</param>        /// <param name="options">Any <see cref="ParallelOptions"/> to apply.</param>        /// <returns>        /// <c>true</c> if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, <c>false</c>.        /// </returns>        /// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam>        /// <exception cref="ArgumentNullException"><paramref name="source" /> or <paramref name="predicate" /> is <c>null</c>.</exception>        public static bool AllParallel<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, ParallelOptions options = null)        {            if ((object)source == null)                throw new ArgumentNullException(nameof(source));             if ((object)predicate == null)                throw new ArgumentNullException(nameof(predicate));             bool succeeded = true;             Parallel.ForEach(source, options ?? new ParallelOptions(), (element, state) =>            {                if (!predicate(element))                {                    succeeded = false;                    state.Break();                }            });             return succeeded;        }         /// <summary>        /// Gets the median item(s) from an enumeration, i.e., one return item for odd lengths, two for even lengths.        /// </summary>        /// <remarks>        /// If enumeration length is even, two items will be returned representing the items in the middle of the set;        /// otherwise, if the enumeration length is odd, one item will be returned from exactly the middle of the set.        /// </remarks>        /// <typeparam name="T"><see cref="Type"/> of elements in the <paramref name="source"/></typeparam>        /// <param name="source">An enumeration over which to find the median element(s).</param>        /// <returns>The median item(s) from an enumeration, or <c>null</c> if <paramref name="source"/> is <c>null</c>.</returns>        public static T[] Median<T>(this IEnumerable<T> source)        {            if ((object)source == null)                return null;             T[] values = source as T[] ?? source.ToArray();             if (values.Length < 3)                return values;             List<T> results = new List<T>();             bool isEven = values.Length % 2 == 0;            int midIndex = values.Length / 2;             if (isEven)                results.Add(values[midIndex - 1]);             results.Add(values[midIndex]);             return results.ToArray();        }         /// <summary>        /// Returns the majority value in the collection, or default type value if no item represents the majority.        /// </summary>        /// <typeparam name="TSource"><see cref="Type"/> of elements in the <paramref name="source"/>.</typeparam>        /// <typeparam name="TKey">The generic type of the objects to be compared.</typeparam>        /// <param name="source">An enumeration over which to find the majority element.</param>        /// <param name="keySelector">A delegate that takes an object and produces the key for comparison.</param>        /// <param name="forwardSearch"><c>true</c> to search forward in <paramref name="source"/>; otherwise <c>false</c> to search backwards.</param>        /// <param name="comparer">The <see cref="IEqualityComparer{TKey}" /> implementation to use when comparing keys, or <c>null</c> to use the default comparer for the type of the key.</param>        /// <returns>The majority value in the collection.</returns>        public static TSource MajorityBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, bool forwardSearch = true, IEqualityComparer<TKey> comparer = null)        {            return source.MajorityBy(default(TSource), keySelector, forwardSearch, comparer);        }         /// <summary>        /// Returns the majority value in the collection, or <paramref name="defaultValue"/> if no item represents the majority.        /// </summary>        /// <typeparam name="TSource"><see cref="Type"/> of elements in the <paramref name="source"/>.</typeparam>        /// <typeparam name="TKey">The generic type of the objects to be compared.</typeparam>        /// <param name="source">An enumeration over which to find the majority element.</param>        /// <param name="defaultValue">Default value to return if no item represents the majority.</param>        /// <param name="keySelector">A delegate that takes an object and produces the key for comparison.</param>        /// <param name="forwardSearch"><c>true</c> to search forward in <paramref name="source"/>; otherwise <c>false</c> to search backwards.</param>        /// <param name="comparer">The <see cref="IEqualityComparer{TKey}" /> implementation to use when comparing keys, or <c>null</c> to use the default comparer for the type of the key.</param>        /// <returns>The majority value in the collection.</returns>        public static TSource MajorityBy<TSource, TKey>(this IEnumerable<TSource> source, TSource defaultValue, Func<TSource, TKey> keySelector, bool forwardSearch = true, IEqualityComparer<TKey> comparer = null)        {            TSource majority = defaultValue;             if ((object)source == null)                return majority;             TSource[] values;             if (forwardSearch)                values = source as TSource[] ?? source.ToArray();            else                values = source.Reverse().ToArray();             if (values.Length > 1)            {                Dictionary<TKey, Tuple<int, TSource>> itemCounts = new Dictionary<TKey, Tuple<int, TSource>>(comparer);                 // Count each number of items in the list                foreach (TSource value in values)                {                    Tuple<int, TSource> valueCount;                    TKey key = keySelector(value);                     if (itemCounts.TryGetValue(key, out valueCount))                    {                        int count = valueCount.Item1 + 1;                        itemCounts[key] = new Tuple<int, TSource>(count, valueCount.Item2);                    }                    else                    {                        itemCounts.Add(key, new Tuple<int, TSource>(1, value));                    }                }                 // Find the largest number of items in the list                KeyValuePair<TKey, Tuple<int, TSource>> maxItem = itemCounts.Max((a, b) => a.Value.Item1 < b.Value.Item1 ? -1 : (a.Value.Item1 > b.Value.Item1 ? 1 : 0));                 // If item with largest count has a plural majority, then it is the majority item                if (maxItem.Value.Item1 > 1)                    majority = maxItem.Value.Item2;            }             return majority;        }         /// <summary>        /// Returns the majority value in the collection, or default type value if no item represents the majority.        /// </summary>        /// <typeparam name="T"><see cref="Type"/> of elements in the <paramref name="source"/>.</typeparam>        /// <param name="source">An enumeration over which to find the majority element.</param>        /// <param name="forwardSearch"><c>true</c> to search forward in <paramref name="source"/>; otherwise <c>false</c> to search backwards.</param>        /// <param name="comparer">The <see cref="IEqualityComparer{T}" /> implementation to use when comparing keys, or <c>null</c> to use the default comparer for the type of the key.</param>        /// <returns>The majority value in the collection.</returns>        public static T Majority<T>(this IEnumerable<T> source, bool forwardSearch = true, IEqualityComparer<T> comparer = null)        {            return source.Majority(default(T), forwardSearch, comparer);        }         /// <summary>        /// Returns the majority value in the collection, or <paramref name="defaultValue"/> if no item represents the majority.        /// </summary>        /// <typeparam name="T"><see cref="Type"/> of elements in the <paramref name="source"/>.</typeparam>        /// <param name="source">An enumeration over which to find the majority element.</param>        /// <param name="defaultValue">Default value to return if no item represents the majority.</param>        /// <param name="forwardSearch"><c>true</c> to search forward in <paramref name="source"/>; otherwise <c>false</c> to search backwards.</param>        /// <param name="comparer">The <see cref="IEqualityComparer{T}" /> implementation to use when comparing keys, or <c>null</c> to use the default comparer for the type of the key.</param>        /// <returns>The majority value in the collection.</returns>        public static T Majority<T>(this IEnumerable<T> source, T defaultValue, bool forwardSearch = true, IEqualityComparer<T> comparer = null)        {            T majority = defaultValue;             if ((object)source == null)                return majority;

Lines 1–500 of 1270.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t