JD2022-TU1/main/tools/framework/JD.Collections/Extensions/CollectionExtensions.cs

251 lines
7.3 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using JD.Collections.Details;
using JD.Collections.ObjectModel;
using JD.Kernel.StaticHelpers;
namespace JD.Collections.Extensions
{
public static class CollectionExtensions
{
#region AddRange
/// <summary>
/// Adds all the <paramref name="items"/> in the <paramref name="collection"/>.
/// </summary>
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items)
{
if (items != null)
{
List<T> list = collection as List<T>;
if (list != null)
{
// List.AddRange is optimized
list.AddRange(items);
}
else
{
items.ForEach(collection.Add);
}
}
}
#endregion
#region AsReadOnly
/// <summary>
/// Returns a read-only wrapper over the given collection.
/// </summary>
public static ICollection<T> AsReadOnly<T>(this ICollection<T> collection)
{
return new ReadOnlyCollection<T>(collection);
}
#endregion
#region IsEmpty
/// <summary>
/// Returns true if the given collection is empty.
/// </summary>
/// <param name="collection"></param>
/// <returns></returns>
public static bool IsEmpty<T>(this ICollection<T> collection)
{
return collection.Count == 0;
}
#endregion
#region Project
/// <summary>
/// Projects (wraps) the collection using the given converter.
/// </summary>
/// <returns>A read-only collection that maps to the original collection.</returns>
public static ICollection<U> Project<U>(this ICollection collection, Converter<object, U> converter)
{
return new NonTypedCollectionWrapper<U>(collection, converter);
}
/// <summary>
/// Projects (wraps) the collection using the given converter.
/// </summary>
/// <returns>A read-only collection that maps to the original collection.</returns>
public static ICollection<U> Project<T, U>(this ICollection<T> collection, Converter<T, U> converter)
{
return new ReadOnlyTypedCollectionWrapper<T, U>(collection, converter);
}
/// <summary>
/// Projects (wraps) the collection using the given converters.
/// </summary>
/// <returns>A collection that maps to the original collection.</returns>
public static ICollection<U> Project<T, U>(this ICollection<T> collection, Converter<T, U> outConverter, Converter<U, T> inConverter)
{
return new TypedCollectionWrapper<T, U>(collection, outConverter, inConverter);
}
#endregion
#region RemoveAll
/// <summary>
/// Removes all the items that match the given <paramref name="predicate"/> from the <paramref name="collection"/>.
/// </summary>
public static int RemoveAll<T>(this ICollection<T> collection, Func<T, bool> predicate)
{
Throw.IfNull(predicate, "predicate");
Throw.InvalidArgumentIf(collection.IsReadOnly, "Collection is read-only", "collection");
IList<T> list = collection as IList<T>;
if (list != null)
{
return list.RemoveAll(predicate);
}
LinkedList<T> removed = new LinkedList<T>();
foreach (T item in collection.Where(predicate))
{
removed.AddLast(item);
}
foreach (T removedItem in removed)
{
collection.Remove(removedItem);
}
return removed.Count;
}
#endregion
#region RemoveRange
/// <summary>
/// Removes all the <paramref name="itemsToRemove"/> from the <paramref name="collection"/>.
/// </summary>
public static void RemoveRange<T>(this ICollection<T> collection, IEnumerable<T> itemsToRemove)
{
if (itemsToRemove != null)
{
itemsToRemove.ForEach(i => collection.Remove(i));
}
}
#endregion
#region SortAndRemoveDuplicates
/// <summary>
/// Sorts and removes the duplicates from the given collection.
/// </summary>
/// <remarks>The algo is optimized for small arrays already sorted without dupplicates.</remarks>
public static T[] SortAndRemoveDuplicates<T>(this ICollection<T> collection)
where T : IComparable<T>
{
T[] array = collection.ToArray();
SortAndRemoveDuplicates(ref array);
return array;
}
/// <summary>
/// Sorts and removes the duplicates from the given collection.
/// </summary>
/// <remarks>The algo is optimized for small arrays already sorted without duplicates.</remarks>
public static void SortAndRemoveDuplicates<T>(ref T[] array)
where T : IComparable<T>
{
if (array.Length > 1)
{
bool duplicates = false;
InsertSort(array, ref duplicates);
if (duplicates)
{
array = RemoveDuplicates(array);
}
}
}
/// <summary>
/// Sort using an insert sort method.
/// </summary>
private static void InsertSort<T>(T[] array, ref bool duplicates)
where T : IComparable<T>
{
int comparison = -1;
for (int j = 1; j < array.Length; j++)
{
T item = array[j];
int i = j - 1;
while (i >= 0 && (comparison = array[i].CompareTo(item)) > 0)
{
array[i + 1] = array[i];
i = i - 1;
}
duplicates |= comparison == 0;
array[i + 1] = item;
}
}
/// <summary>
/// Removes duplicates from a sorted array.
/// </summary>
private static T[] RemoveDuplicates<T>(T[] array)
{
int offset = 0;
for (int i = 1; i < array.Length; i++)
{
if (Equals(array[i], array[i - 1 - offset]))
{
offset++;
}
if (offset > 0)
{
array[i - offset] = array[i];
}
}
Array.Resize(ref array, array.Length - offset);
return array;
}
#endregion
#region Safe
/// <summary>
/// Add an element to a list if it is not null.
/// </summary>
public static void SafeAdd<T>(this ICollection<T> list, T item)
{
if (item != null)
{
list.Add(item);
}
}
/// <summary>
/// Add an element to a list if it is not null.
/// </summary>
public static void SafeRemove<T>(this ICollection<T> list, T item)
{
if (item != null)
{
list.Remove(item);
}
}
#endregion
}
}