251 lines
7.3 KiB
C#
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
|
|
}
|
|
}
|