Related
I'm using ConcurrentQueue for a shared data structure which purpose is holding the last N objects passed to it (kind of history).
Assume we have a browser and we want to have the last 100 browsed Urls. I want a queue which automatically drop (dequeue) the oldest (first) entry upon new entry insertion (enqueue) when the capacity gets full (100 addresses in history).
How can I accomplish that using System.Collections ?
I would write a wrapper class that on Enqueue would check the Count and then Dequeue when the count exceeds the limit.
public class FixedSizedQueue<T>
{
readonly ConcurrentQueue<T> q = new ConcurrentQueue<T>();
private object lockObject = new object();
public int Limit { get; set; }
public void Enqueue(T obj)
{
q.Enqueue(obj);
lock (lockObject)
{
T overflow;
while (q.Count > Limit && q.TryDequeue(out overflow)) ;
}
}
}
I'd go for a slight variant... extend ConcurrentQueue so as to be able to use Linq extensions on FixedSizeQueue
public class FixedSizedQueue<T> : ConcurrentQueue<T>
{
private readonly object syncObject = new object();
public int Size { get; private set; }
public FixedSizedQueue(int size)
{
Size = size;
}
public new void Enqueue(T obj)
{
base.Enqueue(obj);
lock (syncObject)
{
while (base.Count > Size)
{
T outObj;
base.TryDequeue(out outObj);
}
}
}
}
For anyone who finds it useful, here is some working code based on Richard Schneider's answer above:
public class FixedSizedQueue<T>
{
readonly ConcurrentQueue<T> queue = new ConcurrentQueue<T>();
public int Size { get; private set; }
public FixedSizedQueue(int size)
{
Size = size;
}
public void Enqueue(T obj)
{
queue.Enqueue(obj);
while (queue.Count > Size)
{
T outObj;
queue.TryDequeue(out outObj);
}
}
}
For what its worth, here's a lightweight circular buffer with some methods marked for safe and unsafe use.
public class CircularBuffer<T> : IEnumerable<T>
{
readonly int size;
readonly object locker;
int count;
int head;
int rear;
T[] values;
public CircularBuffer(int max)
{
this.size = max;
locker = new object();
count = 0;
head = 0;
rear = 0;
values = new T[size];
}
static int Incr(int index, int size)
{
return (index + 1) % size;
}
private void UnsafeEnsureQueueNotEmpty()
{
if (count == 0)
throw new Exception("Empty queue");
}
public int Size { get { return size; } }
public object SyncRoot { get { return locker; } }
#region Count
public int Count { get { return UnsafeCount; } }
public int SafeCount { get { lock (locker) { return UnsafeCount; } } }
public int UnsafeCount { get { return count; } }
#endregion
#region Enqueue
public void Enqueue(T obj)
{
UnsafeEnqueue(obj);
}
public void SafeEnqueue(T obj)
{
lock (locker) { UnsafeEnqueue(obj); }
}
public void UnsafeEnqueue(T obj)
{
values[rear] = obj;
if (Count == Size)
head = Incr(head, Size);
rear = Incr(rear, Size);
count = Math.Min(count + 1, Size);
}
#endregion
#region Dequeue
public T Dequeue()
{
return UnsafeDequeue();
}
public T SafeDequeue()
{
lock (locker) { return UnsafeDequeue(); }
}
public T UnsafeDequeue()
{
UnsafeEnsureQueueNotEmpty();
T res = values[head];
values[head] = default(T);
head = Incr(head, Size);
count--;
return res;
}
#endregion
#region Peek
public T Peek()
{
return UnsafePeek();
}
public T SafePeek()
{
lock (locker) { return UnsafePeek(); }
}
public T UnsafePeek()
{
UnsafeEnsureQueueNotEmpty();
return values[head];
}
#endregion
#region GetEnumerator
public IEnumerator<T> GetEnumerator()
{
return UnsafeGetEnumerator();
}
public IEnumerator<T> SafeGetEnumerator()
{
lock (locker)
{
List<T> res = new List<T>(count);
var enumerator = UnsafeGetEnumerator();
while (enumerator.MoveNext())
res.Add(enumerator.Current);
return res.GetEnumerator();
}
}
public IEnumerator<T> UnsafeGetEnumerator()
{
int index = head;
for (int i = 0; i < count; i++)
{
yield return values[index];
index = Incr(index, size);
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
I like to use the Foo()/SafeFoo()/UnsafeFoo() convention:
Foo methods call UnsafeFoo as a default.
UnsafeFoo methods modify state freely without a lock, they should only call other unsafe methods.
SafeFoo methods call UnsafeFoo methods inside a lock.
Its a little verbose, but it makes obvious errors, like calling unsafe methods outside a lock in a method which is supposed to be thread-safe, more apparent.
My version is just a subclass of normal Queue ones.. nothing special but seeing everyone participating and it still goes with the topic title I might as well put it here. It also returns the dequeued ones just in case.
public sealed class SizedQueue<T> : Queue<T>
{
public int FixedCapacity { get; }
public SizedQueue(int fixedCapacity)
{
this.FixedCapacity = fixedCapacity;
}
/// <summary>
/// If the total number of item exceed the capacity, the oldest ones automatically dequeues.
/// </summary>
/// <returns>The dequeued value, if any.</returns>
public new T Enqueue(T item)
{
base.Enqueue(item);
if (base.Count > FixedCapacity)
{
return base.Dequeue();
}
return default;
}
}
Just because no one's said it yet.. you can use a LinkedList<T> and add the thread safety:
public class Buffer<T> : LinkedList<T>
{
private int capacity;
public Buffer(int capacity)
{
this.capacity = capacity;
}
public void Enqueue(T item)
{
// todo: add synchronization mechanism
if (Count == capacity) RemoveLast();
AddFirst(item);
}
public T Dequeue()
{
// todo: add synchronization mechanism
var last = Last.Value;
RemoveLast();
return last;
}
}
One thing to note is the default enumeration order will be LIFO in this example. But that can be overridden if necessary.
Here's my take on the fixed size Queue
It uses regular Queue, to avoid the synchronization overhead when the Count property is used on ConcurrentQueue. It also implements IReadOnlyCollection so that LINQ methods can be used. The rest is very similar to the other answers here.
[Serializable]
[DebuggerDisplay("Count = {" + nameof(Count) + "}, Limit = {" + nameof(Limit) + "}")]
public class FixedSizedQueue<T> : IReadOnlyCollection<T>
{
private readonly Queue<T> _queue = new Queue<T>();
private readonly object _lock = new object();
public int Count { get { lock (_lock) { return _queue.Count; } } }
public int Limit { get; }
public FixedSizedQueue(int limit)
{
if (limit < 1)
throw new ArgumentOutOfRangeException(nameof(limit));
Limit = limit;
}
public FixedSizedQueue(IEnumerable<T> collection)
{
if (collection is null || !collection.Any())
throw new ArgumentException("Can not initialize the Queue with a null or empty collection", nameof(collection));
_queue = new Queue<T>(collection);
Limit = _queue.Count;
}
public void Enqueue(T obj)
{
lock (_lock)
{
_queue.Enqueue(obj);
while (_queue.Count > Limit)
_queue.Dequeue();
}
}
public void Clear()
{
lock (_lock)
_queue.Clear();
}
public IEnumerator<T> GetEnumerator()
{
lock (_lock)
return new List<T>(_queue).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Let's add one more answer. Why this over others?
1) Simplicity. Trying to guarantee size is well and good but leads to unneeded complexity that can exhibit its own problems.
2) Implements IReadOnlyCollection, meaning you can use Linq on it and pass it into a variety of things that expect IEnumerable.
3) No locking. Many of the solutions above use locks, which is incorrect on a lockless collection.
4) Implements the same set of methods, properties, and interfaces ConcurrentQueue does, including IProducerConsumerCollection, which is important if you want to use the collection with BlockingCollection.
This implementation could potentially end up with more entries than expected if TryDequeue fails, but the frequency of that occurring doesn't seem worth specialized code that will inevitably hamper performance and cause its own unexpected problems.
If you absolutely want to guarantee a size, implementing a Prune() or similar method seems like the best idea. You could use a ReaderWriterLockSlim read lock in the other methods (including TryDequeue) and take a write lock only when pruning.
class ConcurrentFixedSizeQueue<T> : IProducerConsumerCollection<T>, IReadOnlyCollection<T>, ICollection {
readonly ConcurrentQueue<T> m_concurrentQueue;
readonly int m_maxSize;
public int Count => m_concurrentQueue.Count;
public bool IsEmpty => m_concurrentQueue.IsEmpty;
public ConcurrentFixedSizeQueue (int maxSize) : this(Array.Empty<T>(), maxSize) { }
public ConcurrentFixedSizeQueue (IEnumerable<T> initialCollection, int maxSize) {
if (initialCollection == null) {
throw new ArgumentNullException(nameof(initialCollection));
}
m_concurrentQueue = new ConcurrentQueue<T>(initialCollection);
m_maxSize = maxSize;
}
public void Enqueue (T item) {
m_concurrentQueue.Enqueue(item);
if (m_concurrentQueue.Count > m_maxSize) {
T result;
m_concurrentQueue.TryDequeue(out result);
}
}
public void TryPeek (out T result) => m_concurrentQueue.TryPeek(out result);
public bool TryDequeue (out T result) => m_concurrentQueue.TryDequeue(out result);
public void CopyTo (T[] array, int index) => m_concurrentQueue.CopyTo(array, index);
public T[] ToArray () => m_concurrentQueue.ToArray();
public IEnumerator<T> GetEnumerator () => m_concurrentQueue.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator () => GetEnumerator();
// Explicit ICollection implementations.
void ICollection.CopyTo (Array array, int index) => ((ICollection)m_concurrentQueue).CopyTo(array, index);
object ICollection.SyncRoot => ((ICollection) m_concurrentQueue).SyncRoot;
bool ICollection.IsSynchronized => ((ICollection) m_concurrentQueue).IsSynchronized;
// Explicit IProducerConsumerCollection<T> implementations.
bool IProducerConsumerCollection<T>.TryAdd (T item) => ((IProducerConsumerCollection<T>) m_concurrentQueue).TryAdd(item);
bool IProducerConsumerCollection<T>.TryTake (out T item) => ((IProducerConsumerCollection<T>) m_concurrentQueue).TryTake(out item);
public override int GetHashCode () => m_concurrentQueue.GetHashCode();
public override bool Equals (object obj) => m_concurrentQueue.Equals(obj);
public override string ToString () => m_concurrentQueue.ToString();
}
Just for fun, here is another implementation that I believe addresses most of the commenters' concerns. In particular, thread-safety is achieved without locking and the implementation is hidden by the wrapping class.
public class FixedSizeQueue<T> : IReadOnlyCollection<T>
{
private ConcurrentQueue<T> _queue = new ConcurrentQueue<T>();
private int _count;
public int Limit { get; private set; }
public FixedSizeQueue(int limit)
{
this.Limit = limit;
}
public void Enqueue(T obj)
{
_queue.Enqueue(obj);
Interlocked.Increment(ref _count);
// Calculate the number of items to be removed by this thread in a thread safe manner
int currentCount;
int finalCount;
do
{
currentCount = _count;
finalCount = Math.Min(currentCount, this.Limit);
} while (currentCount !=
Interlocked.CompareExchange(ref _count, finalCount, currentCount));
T overflow;
while (currentCount > finalCount && _queue.TryDequeue(out overflow))
currentCount--;
}
public int Count
{
get { return _count; }
}
public IEnumerator<T> GetEnumerator()
{
return _queue.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _queue.GetEnumerator();
}
}
Well it depends upon the use I have noticed that some of above solution may exceed the size when used in multip-threaded environment. Anyway my use case was to display last 5 events and there are multiple threads writing events into the queue and one other thread reading from it and displaying it in a Winform Control. So this was my solution.
EDIT: Since we already using locking within our implementation we don't really need ConcurrentQueue it may improve the performance.
class FixedSizedConcurrentQueue<T>
{
readonly Queue<T> queue = new Queue<T>();
readonly object syncObject = new object();
public int MaxSize { get; private set; }
public FixedSizedConcurrentQueue(int maxSize)
{
MaxSize = maxSize;
}
public void Enqueue(T obj)
{
lock (syncObject)
{
queue.Enqueue(obj);
while (queue.Count > MaxSize)
{
queue.Dequeue();
}
}
}
public T[] ToArray()
{
T[] result = null;
lock (syncObject)
{
result = queue.ToArray();
}
return result;
}
public void Clear()
{
lock (syncObject)
{
queue.Clear();
}
}
}
EDIT: We don't really need syncObject in above example and we can rather use queue object since we are not re-initializing queue in any function and its marked as readonly anyway.
The accepted answer is going to have avoidable side-effects.
Links below are references that I used when I wrote my example below.
While the documentation from Microsoft is a bit misleading as they do use a lock they however lock the segement classes. The segment classes themselves use Interlocked.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Lib.Core
{
// Sources:
// https://learn.microsoft.com/en-us/dotnet/standard/collections/thread-safe/
// https://learn.microsoft.com/en-us/dotnet/api/system.threading.interlocked?view=netcore-3.1
// https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs
// https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueueSegment.cs
/// <summary>
/// Concurrent safe circular buffer that will used a fixed capacity specified and resuse slots as it goes.
/// </summary>
/// <typeparam name="TObject">The object that you want to go into the slots.</typeparam>
public class ConcurrentCircularBuffer<TObject>
{
private readonly ConcurrentQueue<TObject> _queue;
public int Capacity { get; private set; }
public ConcurrentCircularBuffer(int capacity)
{
if(capacity <= 0)
{
throw new ArgumentException($"The capacity specified '{capacity}' is not valid.", nameof(capacity));
}
// Setup the queue to the initial capacity using List's underlying implementation.
_queue = new ConcurrentQueue<TObject>(new List<TObject>(capacity));
Capacity = capacity;
}
public void Enqueue(TObject #object)
{
// Enforce the capacity first so the head can be used instead of the entire segment (slow).
while (_queue.Count + 1 > Capacity)
{
if (!_queue.TryDequeue(out _))
{
// Handle error condition however you want to ie throw, return validation object, etc.
var ex = new Exception("Concurrent Dequeue operation failed.");
ex.Data.Add("EnqueueObject", #object);
throw ex;
}
}
// Place the item into the queue
_queue.Enqueue(#object);
}
public TObject Dequeue()
{
if(_queue.TryDequeue(out var result))
{
return result;
}
return default;
}
}
}
For your coding pleasure I submit to you the 'ConcurrentDeck'
public class ConcurrentDeck<T>
{
private readonly int _size;
private readonly T[] _buffer;
private int _position = 0;
public ConcurrentDeck(int size)
{
_size = size;
_buffer = new T[size];
}
public void Push(T item)
{
lock (this)
{
_buffer[_position] = item;
_position++;
if (_position == _size) _position = 0;
}
}
public T[] ReadDeck()
{
lock (this)
{
return _buffer.Skip(_position).Union(_buffer.Take(_position)).ToArray();
}
}
}
Example Usage:
void Main()
{
var deck = new ConcurrentDeck<Tuple<string,DateTime>>(25);
var handle = new ManualResetEventSlim();
var task1 = Task.Factory.StartNew(()=>{
var timer = new System.Timers.Timer();
timer.Elapsed += (s,a) => {deck.Push(new Tuple<string,DateTime>("task1",DateTime.Now));};
timer.Interval = System.TimeSpan.FromSeconds(1).TotalMilliseconds;
timer.Enabled = true;
handle.Wait();
});
var task2 = Task.Factory.StartNew(()=>{
var timer = new System.Timers.Timer();
timer.Elapsed += (s,a) => {deck.Push(new Tuple<string,DateTime>("task2",DateTime.Now));};
timer.Interval = System.TimeSpan.FromSeconds(.5).TotalMilliseconds;
timer.Enabled = true;
handle.Wait();
});
var task3 = Task.Factory.StartNew(()=>{
var timer = new System.Timers.Timer();
timer.Elapsed += (s,a) => {deck.Push(new Tuple<string,DateTime>("task3",DateTime.Now));};
timer.Interval = System.TimeSpan.FromSeconds(.25).TotalMilliseconds;
timer.Enabled = true;
handle.Wait();
});
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(10));
handle.Set();
var outputtime = DateTime.Now;
deck.ReadDeck().Select(d => new {Message = d.Item1, MilliDiff = (outputtime - d.Item2).TotalMilliseconds}).Dump(true);
}
Here is yet another implementation that uses the underlying ConcurrentQueue as much as possible while providing the same interfaces made available via ConcurrentQueue.
/// <summary>
/// This is a FIFO concurrent queue that will remove the oldest added items when a given limit is reached.
/// </summary>
/// <typeparam name="TValue"></typeparam>
public class FixedSizedConcurrentQueue<TValue> : IProducerConsumerCollection<TValue>, IReadOnlyCollection<TValue>
{
private readonly ConcurrentQueue<TValue> _queue;
private readonly object _syncObject = new object();
public int LimitSize { get; }
public FixedSizedConcurrentQueue(int limit)
{
_queue = new ConcurrentQueue<TValue>();
LimitSize = limit;
}
public FixedSizedConcurrentQueue(int limit, System.Collections.Generic.IEnumerable<TValue> collection)
{
_queue = new ConcurrentQueue<TValue>(collection);
LimitSize = limit;
}
public int Count => _queue.Count;
bool ICollection.IsSynchronized => ((ICollection) _queue).IsSynchronized;
object ICollection.SyncRoot => ((ICollection)_queue).SyncRoot;
public bool IsEmpty => _queue.IsEmpty;
// Not supported until .NET Standard 2.1
//public void Clear() => _queue.Clear();
public void CopyTo(TValue[] array, int index) => _queue.CopyTo(array, index);
void ICollection.CopyTo(Array array, int index) => ((ICollection)_queue).CopyTo(array, index);
public void Enqueue(TValue obj)
{
_queue.Enqueue(obj);
lock( _syncObject )
{
while( _queue.Count > LimitSize ) {
_queue.TryDequeue(out _);
}
}
}
public IEnumerator<TValue> GetEnumerator() => _queue.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<TValue>)this).GetEnumerator();
public TValue[] ToArray() => _queue.ToArray();
public bool TryAdd(TValue item)
{
Enqueue(item);
return true;
}
bool IProducerConsumerCollection<TValue>.TryTake(out TValue item) => TryDequeue(out item);
public bool TryDequeue(out TValue result) => _queue.TryDequeue(out result);
public bool TryPeek(out TValue result) => _queue.TryPeek(out result);
}
using System.Collections.Concurrent;
public class FixedSizeQueue<T>
{
ConcurrentQueue<T> _queue = new ConcurrentQueue<T>();
private void Enque(T obj)
{
T temp;
if (_queue.Count > 99)
{
// Remove one of the oldest added items.
_queue.TryDequeue(out temp);
}
_queue.Enqueue(obj);
}
private bool Dequeue(out T obj)
{
return _queue.TryDequeue(out obj);
}
private void Clear()
{
T obj;
// It does not fall into an infinite loop, and clears the contents of the present time.
int cnt = _queue.Count;
for (; cnt > 0; cnt--)
{
_queue.TryDequeue(out obj);
}
}
}
This is my version of the queue:
public class FixedSizedQueue<T> {
private object LOCK = new object();
ConcurrentQueue<T> queue;
public int MaxSize { get; set; }
public FixedSizedQueue(int maxSize, IEnumerable<T> items = null) {
this.MaxSize = maxSize;
if (items == null) {
queue = new ConcurrentQueue<T>();
}
else {
queue = new ConcurrentQueue<T>(items);
EnsureLimitConstraint();
}
}
public void Enqueue(T obj) {
queue.Enqueue(obj);
EnsureLimitConstraint();
}
private void EnsureLimitConstraint() {
if (queue.Count > MaxSize) {
lock (LOCK) {
T overflow;
while (queue.Count > MaxSize) {
queue.TryDequeue(out overflow);
}
}
}
}
/// <summary>
/// returns the current snapshot of the queue
/// </summary>
/// <returns></returns>
public T[] GetSnapshot() {
return queue.ToArray();
}
}
I find it useful to have a constructor that is built upon an IEnumerable and I find it useful to have a GetSnapshot to have a multithread safe list (array in this case) of the items at the moment of the call, that doesn't rise errors if the underlaying collection changes.
The double Count check is to prevent the lock in some circumstances.
I am making a prototype application and for that I designed a class that behaves like an infinite looping list. That is, if my internal list contains 100 values, when I ask for the 101st value, I get the first, the 102nd yields the second, and so on, repeating.
So I would like to write the following code:
var slice = loopingListInstance.Skip(123).Take(5);
And for that I need to implement IEnumerable suitable, as I understand.
Here is my current code:
public class InfiniteLoopingList : IEnumerable<double>
{
double[] _values = File.ReadLines(#"c:\file.txt")
.Select(s => double.Parse(s, CultureInfo.InvariantCulture))
.ToArray();
int _size;
public InfiniteLoopingList()
{
_size = _values.Length;
}
public double this[int i]
{
get { return _values[i % _size]; }
set { _values[i % _size] = value; }
}
public IEnumerator<double> GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
// ???? now what ?? :(
}
}
Since you implemented the indexer property, you could do it via the simplest way as follows:
public IEnumerator<double> GetEnumerator()
{
int i = 0;
while (true)
yield return this[i++];
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
EDIT
Please notice, that this is not really infinite loop. This approach will only work until i = int.MaxValue. Thanks to #oleksii.
You don't need a class for this...
An extension method will do the trick:
public static class InfEx
{
public static IEnumerable<T> LoopForever<T>(this IEnumerable<T> src)
{
var data = new List<T>();
foreach(var item in src)
{
data.Add(item);
yield return item;
}
for(;;)
{
foreach(var item in data)
{
yield return item;
}
}
}
}
Now you can take a sequence and make it a looping, infinite sequence:
IEnumerable<Foo> mySeq = ...;
IEnumerable<Foo> infMySeq = mySeq.LoopForver();
IEnumerable<Foo> aSelectionOfInfMySeq = infMySeq.Skip(101).Take(5);
You can implement the IEnumerator interface:
class InifniteEnumerator<T> : IEnumerator<T> {
private int index = -1;
private IList<T> innerList;
private int repeatPos;
public InifniteEnumerator(IList<T> innerList, int repeatPos) {
this.innerList = innerList;
this.repeatPos = repeatPos;
}
public T Current {
get {
if (index == -1) {
throw new InvalidOperationException();
}
return this.innerList[index];
}
}
object IEnumerator.Current {
get {
return this.Current;
}
}
public void Dispose() {
}
public bool MoveNext() {
this.index++;
if (this.index == repeatPos) {
this.index = 0;
}
return true;
}
public void Reset() {
this.index = -1;
}
}
and then return an instance of it in the GetEnumerator methods:
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
public IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return new InifniteEnumerator(this, 100);
}
Is there a collection in C# that will not let you add duplicate items to it? For example, with the silly class of
public class Customer {
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public override int GetHashCode() {
return (FirstName + LastName + Address).GetHashCode();
}
public override bool Equals(object obj) {
Customer C = obj as Customer;
return C != null && String.Equals(this.FirstName, C.FirstName) && String.Equals(this.LastName, C.LastName) && String.Equals(this.Address, C.Address);
}
}
The following code will (obviously) throw an exception:
Customer Adam = new Customer { Address = "A", FirstName = "Adam", LastName = "" };
Customer AdamDup = new Customer { Address = "A", FirstName = "Adam", LastName = "" };
Dictionary<Customer, bool> CustomerHash = new Dictionary<Customer, bool>();
CustomerHash.Add(Adam, true);
CustomerHash.Add(AdamDup, true);
But is there a class that will similarly guarantee uniqueness, but without KeyValuePairs? I thought HashSet<T> would do that, but having read the docs it seems that class is just a set implementation (go figure).
HashSet<T> is what you're looking for. From MSDN (emphasis added):
The HashSet<T> class provides high-performance set operations. A set is a collection that contains no duplicate elements, and whose elements are in no particular order.
Note that the HashSet<T>.Add(T item) method returns a bool -- true if the item was added to the collection; false if the item was already present.
How about just an extension method on HashSet?
public static void AddOrThrow<T>(this HashSet<T> hash, T item)
{
if (!hash.Add(item))
throw new ValueExistingException();
}
From the HashSet<T> page on MSDN:
The HashSet(Of T) class provides high-performance set operations. A set is a collection that contains no duplicate elements, and whose elements are in no particular order.
(emphasis mine)
If all you need is to ensure uniqueness of elements, then HashSet is what you need.
What do you mean when you say "just a set implementation"? A set is (by definition) a collection of unique elements that doesn't save element order.
Just to add my 2 cents...
if you need a ValueExistingException-throwing HashSet<T> you can also create your collection easily:
public class ThrowingHashSet<T> : ICollection<T>
{
private HashSet<T> innerHash = new HashSet<T>();
public void Add(T item)
{
if (!innerHash.Add(item))
throw new ValueExistingException();
}
public void Clear()
{
innerHash.Clear();
}
public bool Contains(T item)
{
return innerHash.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
innerHash.CopyTo(array, arrayIndex);
}
public int Count
{
get { return innerHash.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
return innerHash.Remove(item);
}
public IEnumerator<T> GetEnumerator()
{
return innerHash.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
this can be useful for example if you need it in many places...
You can try HashSet<T>
You may look into something kind of Unique List as follows
public class UniqueList<T>
{
public List<T> List
{
get;
private set;
}
List<T> _internalList;
public static UniqueList<T> NewList
{
get
{
return new UniqueList<T>();
}
}
private UniqueList()
{
_internalList = new List<T>();
List = new List<T>();
}
public void Add(T value)
{
List.Clear();
_internalList.Add(value);
List.AddRange(_internalList.Distinct());
//return List;
}
public void Add(params T[] values)
{
List.Clear();
_internalList.AddRange(values);
List.AddRange(_internalList.Distinct());
// return List;
}
public bool Has(T value)
{
return List.Contains(value);
}
}
and you can use it like follows
var uniquelist = UniqueList<string>.NewList;
uniquelist.Add("abc","def","ghi","jkl","mno");
uniquelist.Add("abc","jkl");
var _myList = uniquelist.List;
will only return "abc","def","ghi","jkl","mno" always even when duplicates are added to it
As an overall check different methods here are 4 ways to check if the collection has not any duplicates:
public static bool LinqAny<T>(IEnumerable<T> enumerable)
{
HashSet<T> set = new();
return enumerable.Any(element => !set.Add(element));
}
public static bool LinqAll<T>(IEnumerable<T> enumerable)
{
HashSet<T> set = new();
return !enumerable.All(set.Add);
}
public static bool LinqDistinct<T>(IEnumerable<T> enumerable)
{
return enumerable.Distinct().Count() != enumerable.Count();
}
public static bool ToHashSet<T>(IEnumerable<T> enumerable)
{
return enumerable.ToHashSet().Count != enumerable.Count();
}
This question already has answers here:
Immutable collections?
(10 answers)
Closed 9 years ago.
It seems to me there is an extreme lack of safe, immutable collection types for .NET, in particular BCL but I've not seen much work done outside either. Do anyone have any pointers to a (preferably) production quality, fast, immutable collections library for .NET. A fast list type is essential. I'm not yet prepared to switch to F#.
*Edit: Note to searchers, this is being rolled into the BCL soon: .NET immutable collections
You might want to take a look at the Microsoft.FSharp.Collections namespace in the FSharp.Core assembly. You do not have to program in F# to make use of these types.
Keep in mind that the names will be different when used from outside F#. For example, the Map in F# is known as FSharpMap from C#.
The .NET BCL team has released a Immutable Collections preview for .NET 4.5
Functional-dotnet by Alexey Romanov
Sasa by Sandro Magi
Kinet by Tony Morris
I wrote an ImmutableList<T> class some time ago :
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class ImmutableList<T> : IList<T>, IEquatable<ImmutableList<T>>
{
#region Private data
private readonly IList<T> _items;
private readonly int _hashCode;
#endregion
#region Constructor
public ImmutableList(IEnumerable<T> items)
{
_items = items.ToArray();
_hashCode = ComputeHash();
}
#endregion
#region Public members
public ImmutableList<T> Add(T item)
{
return this
.Append(item)
.AsImmutable();
}
public ImmutableList<T> Remove(T item)
{
return this
.SkipFirst(it => object.Equals(it, item))
.AsImmutable();
}
public ImmutableList<T> Insert(int index, T item)
{
return this
.InsertAt(index, item)
.AsImmutable();
}
public ImmutableList<T> RemoveAt(int index)
{
return this
.SkipAt(index)
.AsImmutable();
}
public ImmutableList<T> Replace(int index, T item)
{
return this
.ReplaceAt(index, item)
.AsImmutable();
}
#endregion
#region Interface implementations
public int IndexOf(T item)
{
if (_items == null)
return -1;
return _items.IndexOf(item);
}
public bool Contains(T item)
{
if (_items == null)
return false;
return _items.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
if (_items == null)
return;
_items.CopyTo(array, arrayIndex);
}
public int Count
{
get
{
if (_items == null)
return 0;
return _items.Count;
}
}
public IEnumerator<T> GetEnumerator()
{
if (_items == null)
return Enumerable.Empty<T>().GetEnumerator();
return _items.GetEnumerator();
}
public bool Equals(ImmutableList<T> other)
{
if (other == null || this._hashCode != other._hashCode)
return false;
return this.SequenceEqual(other);
}
#endregion
#region Explicit interface implementations
void IList<T>.Insert(int index, T item)
{
throw new InvalidOperationException();
}
void IList<T>.RemoveAt(int index)
{
throw new InvalidOperationException();
}
T IList<T>.this[int index]
{
get
{
if (_items == null)
throw new IndexOutOfRangeException();
return _items[index];
}
set
{
throw new InvalidOperationException();
}
}
void ICollection<T>.Add(T item)
{
throw new InvalidOperationException();
}
void ICollection<T>.Clear()
{
throw new InvalidOperationException();
}
bool ICollection<T>.IsReadOnly
{
get { return true; }
}
bool ICollection<T>.Remove(T item)
{
throw new InvalidOperationException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
#region Overrides
public override bool Equals(object obj)
{
if (obj is ImmutableList<T>)
{
var other = (ImmutableList<T>)obj;
return this.Equals(other);
}
return false;
}
public override int GetHashCode()
{
return _hashCode;
}
#endregion
#region Private methods
private int ComputeHash()
{
if (_items == null)
return 0;
return _items
.Aggregate(
983,
(hash, item) =>
item != null
? 457 * hash ^ item.GetHashCode()
: hash);
}
#endregion
}
All methods that modify the collection return a modified copy. In order to fulfill with the IList<T> interface contract, the standard Add/Remove/Delete/Clear methods are implemented explicitly, but they throw an InvalidOperationException.
This class uses a few non-standard extension methods, here they are :
public static class ExtensionMethods
{
public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T item)
{
return source.Concat(new[] { item });
}
public static IEnumerable<T> SkipFirst<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
bool skipped = false;
foreach (var item in source)
{
if (!skipped && predicate(item))
{
skipped = true;
continue;
}
yield return item;
}
}
public static IEnumerable<T> SkipAt<T>(this IEnumerable<T> source, int index)
{
return source.Where((it, i) => i != index);
}
public static IEnumerable<T> InsertAt<T>(this IEnumerable<T> source, int index, T item)
{
int i = 0;
foreach (var it in source)
{
if (i++ == index)
yield return item;
yield return it;
}
}
public static IEnumerable<T> ReplaceAt<T>(this IEnumerable<T> source, int index, T item)
{
return source.Select((it, i) => i == index ? item : it);
}
}
And here's a helper class to create instances of ImmutableList<T> :
public static class ImmutableList
{
public static ImmutableList<T> CreateFrom<T>(IEnumerable<T> source)
{
return new ImmutableList<T>(source);
}
public static ImmutableList<T> Create<T>(params T[] items)
{
return new ImmutableList<T>(items);
}
public static ImmutableList<T> AsImmutable<T>(this IEnumerable<T> source)
{
return new ImmutableList<T>(source);
}
}
Here's a usage example :
[Test]
public void Test_ImmutableList()
{
var expected = ImmutableList.Create("zoo", "bar", "foo");
var input = ImmutableList.Create("foo", "bar", "baz");
var inputSave = input.AsImmutable();
var actual = input
.Add("foo")
.RemoveAt(0)
.Replace(0, "zoo")
.Insert(1, "bar")
.Remove("baz");
Assert.AreEqual(inputSave, input, "Input collection was modified");
Assert.AreEqual(expected, actual);
}
I can't say it's production quality, as I haven't tested it thoroughly, but so far it seems to work just fine...
C5 springs to mind, but I'm not sure how fast it is. It has been around for years, and is very stable.
Additionally, List<T>.AsReadOnly() does the job rather well IMO, but unfortunately there is no equivalent for dictionaries or arbitrary ICollection<T>'s.
You may look at Extras or System.collections.concurrent tutorial
You could try BclExtras by JaredPar.
I am serializing Lists of classes which are my data entities. I have a DataProvider that contains a List.
I always modify items directly within the collection.
What is the best way of determining if any items in the List have changed? I am using the Compact Framework.
My only current idea is to create a hash of the List (if that's possible) when I load the list. Then when I do a save I re-get the hash of the list and see if they're different values. If they're different I save and then update the stored Hash for comparison later, if they're the same then I don't save.
Any ideas?
If the items you add to the list implement the INotifyPropertyChanged interface, you could build your own generic list that hooks the event in that interface for all objects you add to the list, and unhooks the event when the items are removed from the list.
There's a BindingList<T> class in the framework you can use, or you can write your own.
Here's a sample add method, assuming the type has been declared with where T: INotifyPropertyChanged:
public void Add(T item)
{
// null-check omitted for simplicity
item.PropertyChanged += ItemPropertyChanged;
_List.Add(item);
}
and the this[index] indexer property:
public T this[Int32 index]
{
get { return _List[index]; }
set {
T oldItem = _List[index];
_List[index] = value;
if (oldItem != value)
{
if (oldItem != null)
oldItem.PropertyChanged -= ItemPropertyChanged;
if (value != null)
value.PropertyChanged += ItemPropertyChanged;
}
}
}
If your items doesn't support INotifyPropertyChanged, but they're your classes, I would consider adding that support.
You could create your own IList<T> class, say DirtyList<T> that can record when the list has changed.
If you're willing to use reflection, the List<T> class has a private field called _version that is incremented every time the list changes. It won't tell you which items have changed, but you can compare it with the original value of _version to detect an unmodified list.
For reference, this field is used to ensure that enumerators become invalid when the list is modified. So you should be able to use it for your purposes fairly reliably, unless the actual managed code for List<T> changes.
To get the value of _version you can use something like this:
List<T> myList;
var field = myList.GetType().GetField("_version", BindingFlags.Instance | BindingFlags.NonPublic);
int version = field.GetValue(myList);
Generally speaking, though, this isn't the best approach. If you're stuck using a List<T> that someone else created, however, it's probably the best option you have. Please be aware that changes to the .NET framework could change the name of the field (or remove it entirely), and it's not guaranteed to exist in third-party CLR implementations like Mono.
How about something like this?
public class ItemChangedArgs<T> : EventArgs
{
public int Index { get; set; }
public T Item { get; set; }
}
public class EventList<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable
{
private List<T> m_list;
public event EventHandler<ItemChangedArgs<T>> ItemAdded;
public event EventHandler<ItemChangedArgs<T>> ItemRemoved;
public event EventHandler<ItemChangedArgs<T>> ItemChanged;
public event EventHandler ListCleared;
public EventList(IEnumerable<T> collection)
{
m_list = new List<T>(collection);
}
public EventList(int capacity)
{
m_list = new List<T>(capacity);
}
public EventList()
{
m_list = new List<T>();
}
public void Add(T item)
{
Add(item, true);
}
public void Add(T item, Boolean raiseEvent)
{
m_list.Add(item);
if (raiseEvent) RaiseItemAdded(this.Count - 1, item);
}
public void AddRange(IEnumerable<T> collection)
{
foreach (T t in collection)
{
m_list.Add(t);
}
}
private void RaiseItemAdded(int index, T item)
{
if (ItemAdded == null) return;
ItemAdded(this, new ItemChangedArgs<T> { Index = index, Item = item });
}
public int IndexOf(T item)
{
return m_list.IndexOf(item);
}
public void Insert(int index, T item)
{
m_list.Insert(index, item);
RaiseItemAdded(index, item);
}
public void RemoveAt(int index)
{
T item = m_list[index];
m_list.RemoveAt(index);
RaiseItemRemoved(index, item);
}
private void RaiseItemRemoved(int index, T item)
{
if(ItemRemoved == null) return;
ItemRemoved(this, new ItemChangedArgs<T> { Index = index, Item = item });
}
public T this[int index]
{
get { return m_list[index]; }
set
{
m_list[index] = value;
RaiseItemChanged(index, m_list[index]);
}
}
private void RaiseItemChanged(int index, T item)
{
if(ItemChanged == null) return;
ItemChanged(this, new ItemChangedArgs<T> { Index = index, Item = item });
}
public void Clear()
{
m_list.Clear();
RaiseListCleared();
}
private void RaiseListCleared()
{
if(ListCleared == null) return;
ListCleared(this, null);
}
public bool Contains(T item)
{
return m_list.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
m_list.CopyTo(array, arrayIndex);
}
public int Count
{
get { return m_list.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
for (int i = 0; i < m_list.Count; i++)
{
if(item.Equals(m_list[i]))
{
T value = m_list[i];
m_list.RemoveAt(i);
RaiseItemRemoved(i, value);
return true;
}
}
return false;
}
public IEnumerator<T> GetEnumerator()
{
return m_list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_list.GetEnumerator();
}
}
Assuming that GetHashCode() for every member contained in the list is implemented properly (and thus changes when an element changes) I'd imagine something along the lines of:
public class DirtyList<T> : List<T> {
private IList<int> hashCodes = new List<int> hashCodes();
public DirtyList() : base() { }
public DirtyList(IEnumerable<T> items) : base() {
foreach(T item in items){
this.Add(item); //Add it to the collection
hashCodes.Add(item.GetHashCode());
}
}
public override void Add(T item){
base.Add(item);
hashCodes.Add(item);
}
//Add more logic for the setter and also handle the case where items are removed and indexes change and etc, also what happens in case of null values?
public bool IsDirty {
get {
for(int i = 0; i < Count: i++){
if(hashCodes[i] != this[i].GetHashCode()){ return true; }
}
return false;
}
}
}
*Please be aware i typed this up on SO and do not have a compiler, so above stated code is in no way guarenteed to work, but hopefully it'll show the idea.
You could implement you're own list that maintains 2 internal lists... and instantiated version and tracking version... e.g.
//Rough Psuedo Code
public class TrackedList<T> : List<T>
{
public bool StartTracking {get; set; }
private List<T> InitialList { get; set; }
CTOR
{
//Instantiate Both Lists...
}
ADD(item)
{
if(!StartTracking)
{
Base.Add(item);
InitialList.Add(item);
}
else
{
Base.Add(item);
}
}
public bool IsDirty
{
get
{
Check if theres any differences between initial list and self.
}
}
}
Make sure that T is a descendant of an object that has a dirty flag and have the IList implementation have a check for that which walks the list's dirty flags.