I'm looking for a .Net implementation of a multiset. Can anyone recommend a good one?
(A multiset, or bag, is a set that can have duplicate values, and on which you can do set operations: intersection, difference, etc. A shopping cart for instance could be thought of as a multiset because you can have multiple occurrences of the same product.)
I do not know about one, however you could use a Dictionary for that, in which the value is the quantity of the item. And when the item is added for the second time, you vould increase the value for it in the dictionary.
An other possibility would be to simply use a List of items, in which you could put duplicates. This might be a better approach for a shopping cart.
Anything calling itself a C# implementation of a multiset should not be based on a Dictionary internally. Dictionaries are hash tables, unordered collections. C++'s sets, multisets, maps, and multimaps are ordered. Internally each is represented as some flavor of a self-balancing binary search tree.
In C# we should then use a SortedDictionary as the basis of our implementation as according to Microsoft's own documentation a SortedDictionary "is a binary search tree with O(log n) retrieval". A basic multiset can be implemented as follows:
public class SortedMultiSet<T> : IEnumerable<T>
{
private SortedDictionary<T, int> _dict;
public SortedMultiSet()
{
_dict = new SortedDictionary<T, int>();
}
public SortedMultiSet(IEnumerable<T> items) : this()
{
Add(items);
}
public bool Contains(T item)
{
return _dict.ContainsKey(item);
}
public void Add(T item)
{
if (_dict.ContainsKey(item))
_dict[item]++;
else
_dict[item] = 1;
}
public void Add(IEnumerable<T> items)
{
foreach (var item in items)
Add(item);
}
public void Remove(T item)
{
if (!_dict.ContainsKey(item))
throw new ArgumentException();
if (--_dict[item] == 0)
_dict.Remove(item);
}
// Return the last value in the multiset
public T Peek()
{
if (!_dict.Any())
throw new NullReferenceException();
return _dict.Last().Key;
}
// Return the last value in the multiset and remove it.
public T Pop()
{
T item = Peek();
Remove(item);
return item;
}
public IEnumerator<T> GetEnumerator()
{
foreach(var kvp in _dict)
for(int i = 0; i < kvp.Value; i++)
yield return kvp.Key;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Another option is to just wrap SortedSet, but instead of storing your type T in it, you store the value tuple (T value, int counter) where counter goes up by 1 with each new instance of value that is inserted. Essentially you're forcing the values to be distinct. You can efficiently use GetViewBetween() to find the largest value of counter for a particular value, then increment it to get the counter for a newly-added value. And unlike the count dictionary solution, you can use GetViewBetween() to replicate the functionality equal_range, lower_bound, and upper_bound gives in C++. Here is some code showing what I mean:
public class SortedMultiSet<T> : IEnumerable<T>
{
public void Add(T value)
{
var view = set.GetViewBetween((value, 0), (value, int.MaxValue));
int nextCounter = view.Count > 0 ? view.Max.counter + 1 : 0;
set.Add((value, nextCounter));
}
public bool RemoveOne(T value)
{
var view = set.GetViewBetween((value, 0), (value, int.MaxValue));
if (view.Count == 0) return false;
set.Remove(view.Max);
return true;
}
public bool RemoveAll(T value)
{
var view = set.GetViewBetween((value, 0), (value, int.MaxValue));
bool result = view.Count > 0;
view.Clear();
return result;
}
public SortedMultiSet<T> GetViewBetween(T min, T max)
{
var result = new SortedMultiSet<T>();
result.set = set.GetViewBetween((min, 0), (max, int.MaxValue));
return result;
}
public IEnumerator<T> GetEnumerator() =>
set.Select(x => x.value).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() =>
set.Select(x => x.value).GetEnumerator();
private SortedSet<(T value, int counter)> set =
new SortedSet<(T value, int counter)>();
}
Now you can write something like this:
var multiset = new SortedMultiSet<int>();
foreach (int i in new int[] { 1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 8 })
{
multiset.Add(i);
}
foreach (int i in multiset.GetViewBetween(2, 7))
{
Console.Write(i + " "); // Output: 2 2 3 4 5 5 6 7 7
}
In the past, there were some issues where GetViewBetween() ran in time O(output size), rather than time O(log n), but I think those have been resolved. At the time it would count up nodes to cache the count, it now uses hierarchical counts to perform Count operations efficiently. See this StackOverflow post and this library code.
public class Multiset<T>: ICollection<T>
{
private readonly Dictionary<T, int> data;
public Multiset()
{
data = new Dictionary<T, int>();
}
private Multiset(Dictionary<T, int> data)
{
this.data = data;
}
public void Add(T item)
{
int count = 0;
data.TryGetValue(item, out count);
count++;
data[item] = count;
}
public void Clear()
{
data.Clear();
}
public Multiset<T> Except(Multiset<T> another)
{
Multiset<T> copy = new Multiset<T>(new Dictionary<T, int>(data));
foreach (KeyValuePair<T, int> kvp in another.data)
{
int count;
if (copy.data.TryGetValue(kvp.Key, out count))
{
if (count > kvp.Value)
{
copy.data[kvp.Key] = count - kvp.Value;
}
else
{
copy.data.Remove(kvp.Key);
}
}
}
return copy;
}
public Multiset<T> Intersection(Multiset<T> another)
{
Dictionary<T, int> newData = new Dictionary<T, int>();
foreach (T t in data.Keys.Intersect(another.data.Keys))
{
newData[t] = Math.Min(data[t], another.data[t]);
}
return new Multiset<T>(newData);
}
public bool Contains(T item)
{
return data.ContainsKey(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
foreach (KeyValuePair<T, int> kvp in data)
{
for (int i = 0; i < kvp.Value; i++)
{
array[arrayIndex] = kvp.Key;
arrayIndex++;
}
}
}
public IEnumerable<T> Mode()
{
if (!data.Any())
{
return Enumerable.Empty<T>();
}
int modalFrequency = data.Values.Max();
return data.Where(kvp => kvp.Value == modalFrequency).Select(kvp => kvp.Key);
}
public int Count
{
get
{
return data.Values.Sum();
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
public bool Remove(T item)
{
int count;
if (!data.TryGetValue(item, out count))
{
return false;
}
count--;
if (count == 0)
{
data.Remove(item);
}
else
{
data[item] = count;
}
return true;
}
public IEnumerator<T> GetEnumerator()
{
return new MultisetEnumerator<T>(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return new MultisetEnumerator<T>(this);
}
private class MultisetEnumerator<T> : IEnumerator<T>
{
public MultisetEnumerator(Multiset<T> multiset)
{
this.multiset = multiset;
baseEnumerator = multiset.data.GetEnumerator();
index = 0;
}
private readonly Multiset<T> multiset;
private readonly IEnumerator<KeyValuePair<T, int>> baseEnumerator;
private int index;
public T Current
{
get
{
return baseEnumerator.Current.Key;
}
}
public void Dispose()
{
baseEnumerator.Dispose();
}
object System.Collections.IEnumerator.Current
{
get
{
return baseEnumerator.Current.Key;
}
}
public bool MoveNext()
{
KeyValuePair<T, int> kvp = baseEnumerator.Current;
if (index < (kvp.Value - 1))
{
index++;
return true;
}
else
{
bool result = baseEnumerator.MoveNext();
index = 0;
return result;
}
}
public void Reset()
{
baseEnumerator.Reset();
}
}
}
You can use this implementation of a sorted multiset: SortedMultiSet.cs
Related
Lets say I have a list of items:
[a,b,b,a,c,d,a,d,b,c]
and I need to know, for each item, how many items along do I have to traverse till I get n unique items, (and return eg -1, or otherwise indicate if that's not possible)
So here, if n = 4, I would return
[6,5,4,6,5,5,4,-1,-1,-1]
since
a,b,b,a,c,d contains 4 unique elements
b,b,a,c,d contains 4 unique elements
b,a,c,d contains 4 unique elements,
a,c,d,a,d,b contains 4 unique elements
etc.
I used
List.Select((x,i) => {
var range = List.Skip(i).GroupBy(y => y).Take(n);
if (range.Count() == n)
return range.SelectMany(y => y).Count();
return -1;
});
Although i'm pretty sure this is horribly non-performant.
To try to minimize overhead, I created a ListSpan extension class for managing subparts of a List - something like ArraySegment for List, but (loosely) modeled on Span:
public class ListSpan<T> : IEnumerable<T>, IEnumerable {
List<T> baseList;
int start;
int len;
public ListSpan(List<T> src, int start = 0, int? len = null) {
baseList = src;
this.start = start;
this.len = len ?? (baseList.Count - start);
if (this.start + this.len > baseList.Count)
throw new ArgumentException("start+len > Count for ListSpan");
}
public T this[int n]
{
get
{
return baseList[start + n];
}
set
{
baseList[start + n] = value;
}
}
public class ListSpanEnumerator<Te> : IEnumerator<Te>, IEnumerator {
int pos;
List<Te> baseList;
int end;
Te cur = default(Te);
public ListSpanEnumerator(ListSpan<Te> src) {
pos = src.start - 1;
baseList = src.baseList;
end = src.start + src.len;
}
public Te Current => cur;
object IEnumerator.Current => Current;
public bool MoveNext() {
if (++pos < end) {
cur = baseList[pos];
return true;
}
else {
cur = default(Te);
return false;
}
}
public void Reset() => pos = 0;
public void Dispose() { }
}
public IEnumerator<T> GetEnumerator() => new ListSpanEnumerator<T>(this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public static class ListExt {
public static ListSpan<T> Slice<T>(this List<T> src, int start = 0, int? len = null) => new ListSpan<T>(src, start, len);
}
Then I created an extension method to return the distance (in Take terms) required to get n unique items from an IEnumerable:
public static class IEnumerableExt {
public static int DistanceToUnique<T>(this IEnumerable<T> src, int n, IEqualityComparer<T> cmp = null) {
var hs = new HashSet<T>(cmp ?? EqualityComparer<T>.Default);
var pos = 0;
using (var e = src.GetEnumerator()) {
while (e.MoveNext()) {
++pos;
hs.Add(e.Current);
if (hs.Count == n)
return pos;
}
}
return -1;
}
}
Now the answer is relatively straight forward:
var ans = Enumerable.Range(0, src.Count).Select(p => src.Slice(p).DistanceToUnique(n));
Basically I go through each position in the original (src) List and compute the distance to n unique values from that position using a ListSpan of the List starting at that position.
This still isn't terribly efficient in that I am creating a HashSet for every element in the original List and putting all the following elements in it, and traversing the elements up to k! times for a k element List. Still trying to come up with something really efficient.
I'm trying to solve questions of C# programming in testdome.com, but I found problem about performance. How to solve it?
BinarySearchTree
using System;
public class Node
{
public int Value { get; set; }
public Node Left { get; set; }
public Node Right { get; set; }
public Node(int value, Node left, Node right)
{
Value = value;
Left = left;
Right = right;
}
}
public class BinarySearchTree
{
public static bool Contains(Node root, int value)
{
Console.WriteLine("value=" + value);
if(root == null)
return false;
else if(root.Value == value)
return true;
else if(root.Value != value)
{
return Contains(root.Left, value) | Contains(root.Right, value);
}
return false;
}
public static void Main(string[] args)
{
Node n1 = new Node(1, null, null);
Node n3 = new Node(3, null, null);
Node n2 = new Node(2, n1, n3);
Console.WriteLine(Contains(n2, 3));
}
}
Performance test on a large tree: Memory limit exceeded
https://www.testdome.com/for-developers/solve-question/7482
TwoSum
using System;
using System.Collections.Generic;
class TwoSum
{
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
for(int ctr1=0; ctr1<list.Count; ctr1++)
{
for(int ctr2=0; ctr2<list.Count; ctr2++)
{
if ((ctr1 != ctr2) && (list[ctr1]+list[ctr2] == sum))
return new Tuple<int, int>(ctr1, ctr2);
}
}
return null;
}
public static void Main(string[] args)
{
Tuple<int, int> indices = FindTwoSum(new List<int>() { 1, 3, 5, 7, 9 }, 12);
Console.WriteLine(indices.Item1 + " " + indices.Item2);
}
}
Performance test with a large number of elements: Time limit exceeded
https://www.testdome.com/for-developers/solve-question/8125
For the Binary search tree, testdome.com provides a hint "If a value being searched for is smaller than the value of the node, then the right subtree can be ignored." This cuts memory consumption by half.
public static bool Contains(Node root, int value) {
Console.WriteLine("value=" + value);
if (root == null) {
return false;
}
else if (value == root.Value) {
return true;
}
else if (value < root.Value) {
// Hint 2: If a value being searched for is smaller than the value of the node,
// then the right subtree can be ignored.
return Contains(root.Left, value);
}
else {
return Contains(root.Right, value);
}
return false;
}
For the TwoSum, if we assume that the values in the input array are unique, we can use a dictionary to look up an index by its value (in O(1) time). This relates to the hint "A dictionary can be used to store pre-calculated values, this may allow a solution with O(N) complexity."
// Write a function that, when passed a list and a target sum,
// returns, efficiently with respect to time used,
// two distinct zero-based indices of any two of the numbers,
// whose sum is equal to the target sum.
// If there are no two numbers, the function should return null.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum) {
if (list.Count < 2) {
return null;
}
// Hint 2: A dictionary can be used to store pre-calculated values,
// this may allow a solution with O(N) complexity.
var indexByValue = new Dictionary<int, int>();
for (var i = 0; i < list.Count; i++) {
var value = list[i];
// ensure that the values used as keys are unique
// this is OK because we only have to return any tuple matching the sum,
// therefore we can ignore any duplicate values
if (!indexByValue.ContainsKey(value)) {
indexByValue.Add(value, i);
}
}
for (var j = 0; j < list.Count; j++) {
var remainder = sum - list[j];
if (indexByValue.ContainsKey(remainder)) {
return new Tuple<int, int> (j, indexByValue[remainder]);
}
}
return null;
}
Simpler way to attack the problem. The above answers are good, but think the desired result can be found quicker.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
if (list.Count < 2) { return null; }
foreach (int i in list)
{
int result = sum - i;
if(list.Contains(result))
{
return new Tuple<int, int>(i, result);
}
}
return null;
}
For TwoSum, I found the below link that gives 100% pass on TestDome: Look for JonnyT's answer:
TwoSum 100% Pass
Below is the code as well:
PS: I am only providing this to help others, so please upvote JonnyT's answer instead of mine :)
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
HashSet<int> hs = new HashSet<int>();
for (int i = 0; i < list.Count; i++)
{
var needed = sum - list[i];
if (hs.Contains(needed))
{
return Tuple.Create(list.IndexOf(needed), i);
}
hs.Add(list[i]);
}
return null;
}
public static void Main(string[] args)
{
Tuple<int, int> indices = FindTwoSum(new List<int>() { 3, 1, 5, 7, 5, 9 }, 10);
if (indices != null)
{
Console.WriteLine(indices.Item1 + " " + indices.Item2);
}
}
// This passes all tests
public static bool Contains(Node root, int value)
{
var result = false;
if (root == null) return result;
if (value == root.Value)
{
result = true;
}
else
{
if(value <= root.Value)
{
if(Contains(root.Left, value))
{
result = true;
}
}
else
{
return Contains(root.Right, value);
}
}
return result;
}
For Twosum:
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
if (list.Count < 2)
{
return Tuple<int, int>(0,0);
}
for (var j = 0; j < list.Count; j++)
{
var remainder = sum - list[j];
if (list.Contains(remainder))
{
return new Tuple<int, int>(list[j], remainder);
}
}
return new Tuple<int, int>(0,0);
}
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 it possible to clone just part of a List<T>?
Example:
List<string> myoriginalstring = new List<string>();
myoriginalstring.Add("Tyrannosaurus");
myoriginalstring.Add("Amargasaurus");
myoriginalstring.Add("Mamenchisaurus");
I want to clone myoriginalstring to another list but just from index 1 to index 2.
Is that possible? Changes in the second List<string> should be reflected in first and vice-versa.
UPDATE
Thanks for the answers so far. It seems I didn't express myself correctly.
Actually I don't want to copy or clone. I need to create a new list (which will be some part of the original one); and when I change something (some value) in my new list, the original should be also changed the same way. (The lists should be identical all the time, just the new list will be some part of the original).
Hopefully that is clearer.
You can create a ListSlice<T> class that represents a slice of an existing list. The slice will behave as a read-only list and because it keeps a reference to the original list you are not supposed to add or remove elements in the original list. This cannot be enforced unless you implement your own list but I will not do that here.
You will have to implement the entire IList<T> interface including the IEnumerator<T> you need for enumerating the slice. Here is an example:
class ListSlice<T> : IList<T> {
readonly IList<T> list;
readonly Int32 startIndex;
readonly Int32 length;
public ListSlice(IList<T> list, Int32 startIndex, Int32 length) {
if (list == null)
throw new ArgumentNullException("list");
if (!(0 <= startIndex && startIndex < list.Count))
throw new ArgumentException("startIndex");
if (!(0 <= length && length <= list.Count - startIndex))
throw new ArgumentException("length");
this.list = list;
this.startIndex = startIndex;
this.length = length;
}
public T this[Int32 index] {
get {
if (!(0 <= index && index < this.length))
throw new ArgumentOutOfRangeException();
return this.list[this.startIndex + index];
}
set {
if (!(0 <= index && index < this.length))
throw new ArgumentOutOfRangeException();
this.list[this.startIndex + index] = value;
}
}
public Int32 IndexOf(T item) {
var index = this.list.IndexOf(item);
return index == -1 || index >= this.startIndex + this.length
? -1 : index - this.startIndex;
}
public void Insert(Int32 index, T item) { throw new NotSupportedException(); }
public void RemoveAt(Int32 index) { throw new NotSupportedException(); }
public Int32 Count { get { return this.length; } }
public Boolean IsReadOnly { get { return true; } }
public void Add(T item) { throw new NotSupportedException(); }
public void Clear() { throw new NotSupportedException(); }
public Boolean Contains(T item) { return IndexOf(item) != -1; }
public void CopyTo(T[] array, Int32 arrayIndex) {
for (var i = this.startIndex; i < this.length; i += 1)
array[i + arrayIndex] = this.list[i];
}
public Boolean Remove(T item) { throw new NotSupportedException(); }
public IEnumerator<T> GetEnumerator() {
return new Enumerator(this.list, this.startIndex, this.length);
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
class Enumerator : IEnumerator<T> {
readonly IList<T> list;
readonly Int32 startIndex;
readonly Int32 length;
Int32 index;
T current;
public Enumerator(IList<T> list, Int32 startIndex, Int32 length) {
this.list = list;
this.startIndex = startIndex;
this.length = length;
}
public T Current { get { return this.current; } }
Object IEnumerator.Current {
get {
if (this.index == 0 || this.index == this.length + 1)
throw new InvalidOperationException();
return Current;
}
}
public Boolean MoveNext() {
if (this.index < this.length) {
this.current = this.list[this.index + this.startIndex];
this.index += 1;
return true;
}
this.current = default(T);
return false;
}
public void Reset() {
this.index = 0;
this.current = default(T);
}
public void Dispose() {
}
}
}
You can write an extension method to make it easier to work with slices:
static class ListExtensions {
public static ListSlice<T> Slice<T>(this IList<T> list, Int32 startIndex, Int32 length) {
return new ListSlice<T>(list, startIndex, length);
}
}
To use the slice you can write code like this:
var list = new List<String> {
"Tyrannosaurus",
"Amargasaurus",
"Mamenchisaurus"
};
var slice = list.Slice(1, 2);
slice[0] = "Stegosaurus";
Now list[1] as well as slice[0] contains "Stegosaurus".
Assuming you really did mean clone and not copy...
List<string> myoriginalstring = new List<string> { "Tyrannosaurus", "Amargasaurus", "Mamenchisaurus" };
List<string> myCloneString = myoriginalstring.GetRange(1, myoriginalstring.Count() -1 );
On the first glance, it seems as if
var list2 = myoriginalstring.SkipWhile((str, i)=>!(i>=1 && i<=2)).ToList();
list2[1]="Stegosaurus";
would be the solution. But it is not, because list2 is a independent list which contains its own elements. The code above works, but it replaces only the element in the (new) list2, not in myoriginalstring.
As you pointed out, this is not what you wanted to do.
Solution
Unlike other languages like C, you don't have access to pointers directly in C#.
Hence, the solution is more complex. Instead of using strings directly, you need to create an object, like the following:
public class Dino
{
public string Value { get; set; }
public object[] Parent { get; set; }
public int ParentIndex;
}
Then, create some helper extension methods, like so:
public static class Extensions
{
public static Dino AsDino(this string name)
{
return new Dino() {Value=name};
}
public static Dino AsDino(this string name, object[] reference, int parentIndex)
{
return new Dino() {Value=name, Parent=reference, ParentIndex=parentIndex };
}
public static Dino Replace(this object item, Dino replacementItem)
{
replacementItem.ParentIndex=((Dino)item).ParentIndex;
replacementItem.Parent=((Dino)item).Parent;
((Dino)item).Parent[replacementItem.ParentIndex]=replacementItem;
return replacementItem;
}
}
With those helpers, you can do it:
// create array with 3 elements
var myoriginalstring = new object[3];
// fill in the dinosours and keep track of the array object and positions within
myoriginalstring[0]="Tyrannosaurus".AsDino(myoriginalstring, 0);
myoriginalstring[1]="Amargasaurus".AsDino(myoriginalstring, 1);
myoriginalstring[2]="Mamenchisaurus".AsDino(myoriginalstring, 2);
// get a subset of the array
var list2 = myoriginalstring.SkipWhile((str, i)=>!(i>=1 && i<=2)).ToList<object>();
// replace the value at index 1 in list2. This will also replace the value
// in the original array myoriginalstring
list2[1].Replace("Stegosaurus".AsDino());
The trick is, that the Dino class keeps track of its origin (the array myoriginalstring) and the position within it (i.e. its index).
What is the most efficient (in terms of speed) implementation of UniqueQueue and UniqueReplacementQueue collections in .NET considering the fact that the speed of Enqueue and Dequeue operations is equally important.
UniqueQueue is a queue where duplicates are not possible. So if I push an element to the queue it is added in only case it doesn't already exist in the queue.
UniqueReplacementQueue is a queue where duplicates are not possible either. The difference is that if I push an element which already exists in the queue, it replaces the existing element at the same position. It makes sense for reference types.
My current implementation of UniqueQueue and UniqueReplacementQueue:
sealed class UniqueQueue<T> : IQueue<T>
{
readonly LinkedList<T> list;
readonly IDictionary<T, int> dictionary;
public UniqueQueue(LinkedList<T> list, IDictionary<T, int> dictionary)
{
this.list = list;
this.dictionary = dictionary;
}
public int Length
{
get { return list.Count; }
}
public T Dequeue()
{
if (list.Count == 0)
{
throw new InvalidOperationException("The queue is empty");
}
var element = list.First.Value;
dictionary.Remove(element);
list.RemoveFirst();
return element;
}
public void Enqueue(T element)
{
dictionary[element] = 0;
if (dictionary.Count > list.Count)
{
list.AddLast(element);
}
}
}
sealed class UniqueReplacementQueue<T> : IQueue<T>
{
readonly LinkedList<T> list;
readonly IDictionary<T, T> dictionary;
public UniqueReplacementQueue(LinkedList<T> list, IDictionary<T, T> dictionary)
{
this.list = list;
this.dictionary = dictionary;
}
public int Length
{
get { return list.Count; }
}
public T Dequeue()
{
if (list.Count == 0)
{
throw new InvalidOperationException("The queue is empty");
}
var element = dictionary[list.First.Value];
dictionary.Remove(element);
list.RemoveFirst();
return element;
}
public void Enqueue(T element)
{
dictionary[element] = element;
if (dictionary.Count > list.Count)
{
list.AddLast(element);
}
}
}
This is pretty old, but how about a class that has an internal HashSet, and Queue. A custom method for Enqueue firsts tries to add it to the hashset. if the HashSet.Add call returns false, we do not enqueue it. HashSet.Add() is an O(1) operation if the set is of a size large enough to hold all elements.
The only drawback to this is memory usage if this is a concern for you. Here is an implementation:
public class UniqueQueue<T> : IEnumerable<T> {
private HashSet<T> hashSet;
private Queue<T> queue;
public UniqueQueue() {
hashSet = new HashSet<T>();
queue = new Queue<T>();
}
public int Count {
get {
return hashSet.Count;
}
}
public void Clear() {
hashSet.Clear();
queue.Clear();
}
public bool Contains(T item) {
return hashSet.Contains(item);
}
public void Enqueue(T item) {
if (hashSet.Add(item)) {
queue.Enqueue(item);
}
}
public T Dequeue() {
T item = queue.Dequeue();
hashSet.Remove(item);
return item;
}
public T Peek() {
return queue.Peek();
}
public IEnumerator<T> GetEnumerator() {
return queue.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return queue.GetEnumerator();
}
}
The HashSet is used whenever it can because it is typically faster. This could be nicer if the maintainers of .NET marked these methods as virtual, but alas here we are.
How about this?
//the UniqueQueueItem has the key in itself,
//and implements the IUniqueQueueItemable to copy the other values.
//For example:
class TestUniqueQueueItem : IUniqueQueueItemable<TestUniqueQueueItem>
{
//Key
public int Id { get; set; }
public string Name { get; set; }
public override int GetHashCode()
{
return Id;
}
//To copy the other values.
public void CopyWith(TestUniqueQueueItem item)
{
this.Name = item.Name;
}
public override bool Equals(object obj)
{
return this.Id == ((TestUniqueQueueItem)obj).Id;
}
}
internal interface IUniqueQueueItemable<in T>
{
void CopyWith(T item);
}
class UniqueQueue<T> where T: IUniqueQueueItemable<T>
{
private readonly bool _isReplacementQueue;
private readonly Queue<T> _queue;
private readonly Dictionary<T, T> _dictionary;
public UniqueQueue(): this(false)
{
}
public UniqueQueue(bool isReplacementQueue)
{
_isReplacementQueue = isReplacementQueue;
_queue = new Queue<T>();
_dictionary = new Dictionary<T, T>();
}
public void Enqueue(T item)
{
if(!_dictionary.Keys.Contains(item))
{
_dictionary.Add(item, item);
_queue.Enqueue(item);
}
else
{
if(_isReplacementQueue)
{
//it will return the existedItem, which is the same key with the item
//but has different values with it.
var existedItem = _dictionary[item];
//copy the item to the existedItem.
existedItem.CopyWith(item);
}
}
}
public T Dequeue()
{
var item = _queue.Dequeue();
_dictionary.Remove(item);
return item;
}
}