Increasing performance in custom sorting of a string array - c#

I am trying to find an efficient way to sort an array of strings based on a numeric value within each string element of the array. I am currently using the Array.Sort(array, customComparer) static method (quick sort), with my custom comparer class (sorting in descending order) being:
class StringComparer : IComparer<string>
{
public int Compare(string a, string b)
{
string s1 = a;
string s2 = b;
Match matchA = Regex.Match(s1, #"\d+$");
Match matchB = Regex.Match(s2, #"\d+$");
long numberA = long.Parse(matchA.Value);
long numberB = long.Parse(matchB.Value);
if (numberB - numberA < 0)
{
return -1;
}
else
{
return 1;
}
}
}
This works very well, but sometimes it takes too much time to sort, with an array of 100 000 strings taking more than a minute on a 2.4Ghz processor. I wonder if there is a more efficient way to accomplish the same. For example, implementing a different sorting algorithm or taking another approach like using a dictionary and sorting on the value (the value being the numeric part of the string). Any suggestions? Thanks in advance!

You're parsing the value for each comparison. I would suggest you parse once, to get a string/long pair, sort that, and then extract the string part afterwards.
Note that your existing code has a bug: it will never return 0, for two strings comparing as equal.
Here's an alternative approach using LINQ (which isn't in-place sorting, but is simple.)
var sorted = unsorted.OrderBy(x => long.Parse(Regex.Match(x, #"\d+$").Value));
.ToList();
(OrderBy projects once to get the keys, then compares keys.)

You are now performing the Regexes O(n log n) times.
Consider looping once over all strings, extracting the numerical value and adding it to a SortedDictionary<long, string>
This requires only O(n) executions of the Reg expression. The rest of the sorting should be comparable.

First, you're needlessly parsing the same string over and over (both matching with the regular expression and then parsing the matches). Instead, encapsulate what you have into a custom type so that you only have to parse once.
public class FooString {
private readonly string foo;
private readonly long bar;
public FooString(string foo) {
this.foo = foo;
Match match = Regex.Match(foo, #"\d+$");
this.bar = Int64.Parse(match.Value);
}
public string Foo { get { return this.foo; } }
public long Bar { get { return this.bar; } }
}
I'd even add a Contract.Requires to this class that says that foo must satisfy the regular expression.
Second, you have an IComparer<T> that dies on certain values of T (in your case, strings that don't match the regular expression and can't be parsed to a long). This is generally a bad idea.
So, make the comparer for FooString:
public FooStringComparer : IComparer<FooString> {
public int Compare(FooString a, FooString b) {
Contract.Requires(a != null);
Contract.Requires(b != null);
return a.Bar.CompareTo(b.Bar);
}
}
Now, your sorting will be blazingly fast because you've stopped parsing the same string over and over.

Create the Regex only once with the Compiled option. This will increase the speed.
class StringComparer : IComparer<string>
{
private static Regex _regex = new Regex(#"\d+$", RegexOptions.Compiled);
public int Compare(string a, string b)
{
long numberA = Int64.Parse(_regex.Match(a).Value);
long numberB = Int64.Parse(_regex.Match(b).Value);
return numberA.CompareTo(numberB);
}
}

Related

C# Class/Object passing (Array of Objects)

Right so i have a class I'm using to store a set of values
public class dataSet
{
public int Number;
public double Decimal;
public string Text;
//etc...
}
Then I've made an array of type dataSet
public static dataSet[] dataOne = new dataSet[100];
And i'm trying to sort the array of dataOne relevant to the values stored in the int Number stored within dataSet.
I have a sort algorithm ready but i'm struggling to pass in the values stored solely in dataOne.Number so it just ends up being an integer array that i'm passing to the sort.
I'm a total noob at programming so any help would be greatly appreciated.
Edit:
I need to call my sort function by passing it in the array of dataOne.Number if this is possible? So it's basically just passing the sort function an int[]
Give you already have data into your array named dataOne, you could try:
Linq Solution
Use linq to sort it, try this:
dataOne = dataOne.OrderBy(x => x.Number).ToArray();
Remember to add the namespace System.Linq to have access into these methods.
OrderBy allows you to pass an expression to sort data and it will return an IOrderedEnumerable. The ToArray will convert it to an array.
Not Linq Solution
If you are not allowed to use Linq. You could implement an class that implements IComparer<T> and implement the method Compare which takes two generics arguments. Use an instance of this comparer type to sort your data.
For sample, since you have your dataSet type defined, you could implement the comparer:
public class DataSetComparer : IComparer<dataSet>
{
public int Compare(dataSet x, dataSet y)
{
// define the logic to sort here...
return x.Number.CompareTo(y.Number);
}
}
And then, use the comparer on the Array.Sort method:
Array.Sort(dataSet, new NumberComparer());
It will order your dataSets.
I'm not sure I follow why you can't use Linq. But that forces you do to something like this:
var numberValues = new List<int>();
foreach(var dataItem in dataOne)
{
numberValues.Add(dataItem.Number);
}
Then you could pass numberValues.ToArray() to your sort method.
With Linq it would just be
dataOne.Select(d => d.Number).ToArray()
You should have dataset implement IComparable that way you can easily just do...
dataOne = dataOne.OrderBy(x => x).ToArray();
OR...
Array.Sort(dataOne);
Here is how to implement IComparable...
public class dataSet : IComparable
{
public int Number;
public double Decimal;
public string Text;
public int CompareTo(object obj)
{
if (obj == null)
return 1;
dataSet other = obj as dataSet;
if (other != null)
return this.Number.CompareTo(other.Number);
else
throw new ArgumentException("Object is not a dataSet");
}
}

Avoiding out of range issues in generic functions

I come from the Wild Wild West of PHP and Javascript where you can return anything from a function. While I do hate that lack of accountability, I also face a new challenge in my effort to keep my code "perfect".
I made this generic function to pick a random element from a list
public static T PickRandom<T>(this IList<T> list) {
Random random = new Random();
int rnd = random.Next(list.Count);
return list[rnd];
}
But I want to protect myself from using it on a list with 0 values. Obviously I cannot return anything from this function other than T, such as false or -1. I can of course do this
if(myList.Count > 0)
foo = Utilites.PickRandom(myList);
However there are so many crazy things in C# that I don't know about, and for this app I am creating I very, very often have to choose a random element from a list that could be constantly decrementing in its Count. Is there a better way?
The options you have are
return default(T)
which will be an ambiguous behavior, as that might be a valid element of the list.
Or you can return something like -1 as you said, but that's quite coupled to your code.
Or you can return null, but that can only be done if T is a nullable type, of course.
In all previous cases, if the caller is not aware of this situation, the application may continue with an invalid value, leading to unknown consequences.
So probably the best option is to throw an exception:
throw new InvalidOperationException();
With this approach, you fail fast and you make sure nothing unexpected occurs beyond the caller's intentions.
One reason more to back up this option. Take for example Linq's extension methods. If you call First(), Single() or Last() on an empty list, you will get an InvalidOperationException with the message "Sequence contains no elements". Giving your class a behavior similar to the framework classes' is always a good thing.
I'm adding a side note thanks to Alexei Levenkov's comment in the question. That random generation is not the best approach. Take a look at this question.
Second side note. You are declaring your function as an extension method for IList<T> (you do that by using the this before the first parameter) but then you call it just like a static helper method. An extension method is a syntactic sugar that, instead of doing this:
foo = Utilites.PickRandom(myList);
lets you do this:
foo = myList.PickRandom();
More info on extension methods can be found here.
Another alternative is the following pair of overloads instead the original. With these, it should be clear to the caller that they are to supply a default random value in the event one cannot be "picked" from the list.
public static T PickRandomOrReturnDefault<T>(this IList<T> list, T defaultRandomValue)
{
if (list == null || list.Count == 0) return defaultRandomValue;
Random random = new Random();
int rnd = random.Next(list.Count);
return list[rnd];
}
public static T PickRandomOrReturnDefault<T>(this IList<T> list, Func<T> createRandomValue)
{
if (list == null || list.Count == 0) return createRandomValue();
Random random = new Random();
int rnd = random.Next(list.Count);
return list[rnd];
}
Note: You should probably consider making random a static member field of the class rather than re-instantiating it over and over. See the answer for this post Correct method of a "static" Random.Next in C#?
Another option you have is to use the Maybe<T> monad. It's very much like Nullable<T>, but works with reference types.
public class Maybe<T>
{
public readonly static Maybe<T> Nothing = new Maybe<T>();
public T Value { get; private set; }
public bool HasValue { get; private set; }
public Maybe()
{
HasValue = false;
}
public Maybe(T value)
{
Value = value;
HasValue = true;
}
public static implicit operator Maybe<T>(T v)
{
return v.ToMaybe();
}
}
Your code could then look like this:
private static Random random = new Random();
public static Maybe<T> PickRandom<T>(this IList<T> list)
{
var result = Maybe<T>.Nothing;
if (list.Any())
{
result = list[random.Next(list.Count)].ToMaybe();
}
return result;
}
You would use it like:
var item = list.PickRandom();
if (item.HasValue) { ... }
Personally, I name my maybe methods with Maybe at the end.
It would be more like this:
var itemMaybe = list.PickRandomMaybe();
if (itemMaybe.HasValue) { ... }

Is there a way to derive IEqualityComparer from IComparer?

TL;DR I'm looking for a way to obtain IEqualityComparer<T> from IComparer<T>, no matter which datatype is T, including case-insensitive options if T is string. Or I need a different solution for this problem.
Here's full story: I'm implementing simple, generic cache with LFU policy. Requirement is that it must be possible to select whether the cache will be case sensitive or case insensitive -- if string happens to be the datatype for cache keys (which is not necessary). In the solution I primarily develop the cache for, I expect hundreds of billions of cache lookups, and cache sizes of max 100.000 entries. Because of that numbers I immediately resigned from using any string manipulation that causes allocations (such as .ToLower().GetHashCode() etc.) and instead opted to use IComparer and IEqualityComparer, as they are standard BCL features. User of this cache can pass the comparers to constructor. Here are relevant fragments of the code:
public class LFUCache<TKey,TValue>
{
private readonly Dictionary<TKey,CacheItem> entries;
private readonly SortedSet<CacheItem> lfuList;
private class CacheItem
{
public TKey Key;
public TValue Value;
public int UseCount;
}
private class CacheItemComparer : IComparer<CacheItem>
{
private readonly IComparer<TKey> cacheKeyComparer;
public CacheItemComparer(IComparer<TKey> cacheKeyComparer)
{
this.cacheKeyComparer = cacheKeyComparer;
if (cacheKeyComparer == null)
this.cacheKeyComparer = Comparer<TKey>.Default;
}
public int Compare(CacheItem x, CacheItem y)
{
int UseCount = x.UseCount - y.UseCount;
if (UseCount != 0) return UseCount;
return cacheKeyComparer.Compare(x.Key, y.Key);
}
}
public LFUCache(int capacity, IEqualityComparer<TKey> keyEqualityComparer,
IComparer<TKey> keyComparer) // <- here's my problem
{
// ...
entries = new Dictionary<TKey, CacheItem>(keyEqualityComparer);
lfuList = new SortedSet<CacheItem>(new CacheItemComparer(keyComparer));
}
// ...
}
The keyEqualityComparer is used to manage cache entries (so e.g. the key "ABC" and "abc" are equal if user wants to). The keyComparer is used to manage cache entries sorted by UseCount so that it's easy to select the least frequently used one (implemented in CacheItemComparer class).
Example correct usage with custom comparison:
var cache = new LFUCache<string, int>(10000,
StringComparer.InvariantCultureIgnoreCase,
StringComparer.InvariantCultureIgnoreCase);
(That looks stupid, but StringComparer implements both IComparer<string> and IEqualityComparer<string>.) The problem is that if user gives incompatible comparers (i.e. case insensitive keyEqualityComparer and case sensitive keyComparer), then the most likely outcome is invalid LFU statistics, and thus lower cache hits at best. The other scenario is also less than desired. Also if the key is more sophisticated (I'll have something resembling Tuple<string,DateTime,DateTime>), it's possible to mess it up more severely.
That's why I'd like to only have a single comparer argument in constructor, but that doesn't seem to work. I'm able to create IEqualityComparer<T>.Equals() with help of IComparer<T>.Compare(), but I'm stuck at IEqualityComparer<T>.GetHashCode() -- which is very important, as you know. If I had got access to private properties of the comparer to check if it's case sensitive or not, I would have used CompareInfo to get hash code.
I like this approach with 2 different data structures, because it gives me acceptable performance and controllable memory consumption -- on my laptop around 500.000 cache additions/sec with cache size 10.000 elements. Dictionary<TKey,TValue> is just used to find data in O(1), and SortedSet<CacheItem> inserts data in O(log n), find element to remove by calling lfuList.Min in O(log n), and find the entry to increment use count also in O(log n).
Any suggestions on how to solve this are welcome. I'll appreciate any ideas, including different designs.
It's not possible to implement an IComparer from an IEqualityComparer as you have no way of knowing whether an unequal item is greater than or less than the other item.
It's not possible to implement an IEqualityComparer from an IComparer as there's no way for you to generate a hash code that is in line with the IComparer's identity.
That said, there's no need for you to have both types of comparers in your case. When computing LRU you're comparing the time since an item was used as the primary comparer and then comparing based on a passed in comparer as a tiebreaker. Just remove that last part; don't have a tiebreaker. Let it be undefined which item leaves the cache when there is a tie for the least recently used. When you do that you only need to accept an IEqualityComparer, not an IComparer.
As I alluded to in my comment, you could add a helper method that might make things a little simpler for a basic use case:
public class LFUCache<TKey,TValue>
{
public static LFUCache<TKey, TValue> Create<TComp>(int capacity, TComp comparer) where TComp : IEqualityComparer<TKey>, IComparer<TKey>
{
return new LFUCache<TKey, TValue>(capacity, comparer, comparer);
}
}
and you'd use it like this:
var cache = LFUCache<string, int>.Create(10000, StringComparer.InvariantCultureIgnoreCase);
Okay next try. Here is an implementation for Add and Touch for LFU:
public class LfuCache<TKey, TValue>
{
private readonly Dictionary<TKey, LfuItem> _items;
private readonly int _limit;
private LfuItem _first, _last;
public LfuCache(int limit, IEqualityComparer<TKey> keyComparer = null)
{
this._limit = limit;
this._items = new Dictionary<TKey,LfuItem>(keyComparer);
}
public void Add(TKey key, TValue value)
{
if (this._items.Count == this._limit)
{
this.RemoveLast();
}
var lfuItem = new LfuItem { Key = key, Value = value, Prev = this._last };
this._items.Add(key, lfuItem);
if (this._last != null)
{
this._last.Next = lfuItem;
lfuItem.Prev = this._last;
}
this._last = lfuItem;
if (this._first == null)
{
this._first = lfuItem;
}
}
public TValue this[TKey key]
{
get
{
var lfuItem = this._items[key];
++lfuItem.UseCount;
this.TryMoveUp(lfuItem);
return lfuItem.Value;
}
}
private void TryMoveUp(LfuItem lfuItem)
{
if (lfuItem.Prev == null || lfuItem.Prev.UseCount >= lfuItem.UseCount) // maybe > if you want LRU and LFU
{
return;
}
var prev = lfuItem.Prev;
prev.Next = lfuItem.Next;
lfuItem.Prev = prev.Prev;
prev.Prev = lfuItem;
if (lfuItem.Prev == null)
{
this._first = lfuItem;
}
}
private void RemoveLast()
{
if (this._items.Remove(this._last.Key))
{
this._last = this._last.Prev;
if (this._last != null)
{
this._last.Next = null;
}
}
}
private class LfuItem
{
public TKey Key { get; set; }
public TValue Value { get; set; }
public long UseCount { get; set; }
public LfuItem Prev { get; set; }
public LfuItem Next { get; set; }
}
}
In my opinion it looks like that Add and Touch is in O(1), isn't it?
Currently I don't see any use case for _first but maybe anyone else need it. To remove an item _last should be enough.
EDIT
A single linked list will also do if you don't need a MoveDown operation.
EDIT No a single linked list will not work because MoveUp need the Next pointer to change it's Prev pointer.
Instead of taking an IEqualityComparer and an IComparer in your constructor, you could try taking an IComparer and a lambda which defines GetHashCode(). Then build an IEqualityComparer based on if(IComparer==0) and GetHashCode() = lambda.
Although I would say it is small, you still have the risk of getting HashCode mismatches when IComparer returns 0. If you want to make it super clear to the user of your code, you could always extend the strategy by taking two lambdas in the constructor: Func<T,T,int> used for both IComparer and IEqualityComparer, and Func<T,int> for GetHashCode.

multiple generic overloads

I have a simple helper class that I use to build a simple comma separated string.
private string AddcsvString(string s)
{
if(string.IsNullOrWhiteSpace(this.Value))
{
return s;
}
else
{
return this.Value + "," + s;
}
}
I also have a generic method that calls this
public void Add<T>(T s) where T: struct
{
this.Value = AddcsvString(s.ToString());
}
I wanted to add an overload for a generic List
public void Add<T>(IEnumerable<T> values)where T:struct
{
foreach (T t in values)
{
Add(t.ToString());
}
}
But any attempt to call this called the first generic method. So I ended up renaming the second generic method to AddAll. In the end I think this was the right way to go for this case but would like to know if it is possible to have both for future reference.
--edit
Here is the case that doesn't work
CsvString test = new CsvString();
string result;
test.Add(1);
test.Add('2');
test.Add("3");
result = test.ToString(); // result = "1,2,3"
CsvString test2 = new CsvString();
List<long> aList = new List<long>();
string result2;
aList.Add(1);
aList.Add(2);
aList.Add(3);
test2.Add(aList); //line doesn't compile
--edit 2
I found a second solution (though JoshE below gets credit for answering this, thanks btw).
I changed the second method to this
public SWcsvString Add<T,K>(T values)where T: IEnumerable<K> where K: struct
{
foreach (K k in values)
{
Add(k.ToString());
}
return this;
}
and the call to this
test2.Add<IEnumerable<long>,long>(aList);
Try removing your constraints where T : struct, and I think you will get the proper behavior.
IEnumerable<char> <==> String, since a string is just a char[]. Since a string is not really a value-object, overload resolution will almost always favor the first method to avoid the boxing/unboxing operation of converting a string to IEnumerable<char>. (I'm guessing that you've tried calling it with both "foo" and IEnumerable<bar> where bar is a struct).

Immutable collection in C# that supports (String-like) methods such as "Contains(IEnumerable<T>)"?

String class represents "a collection of chars" and is immutable. It's indexer has only get function defined and it's ok since Char "struct" is immutable as well. All of String's methods that are used for manipulation return new instances of String class.
I recently needed an immutable generic collection that's exactly like String (Let's call it Foo<T>).
It should be generic (though I'll only use it with structs).
It should be immutable.
It should have methods for sequences of items, for example:
IndexOf(Foo<T>) or IndexOf(IEnumerable<T>)
StartsWith(Foo<T>) or StartsWith(IEnumerable<T>)
EndsWith(Foo<T>) or EndsWith(IEnumerable<T>)
Take(int, int) (with start index and length, just like Substring)
Contains(Foo<T>) or Contains(IEnumerable<T>)
LastIndexOf(Foo<T>) or LastIndexOf(IEnumerable<T>)
etc.
I created an immutable class for read-only access to its items and wrote some extension methods to mimic String's functionality but I really have doubts about efficiency of my implementation (I actually asked for Replace method, here). I'm curious about alternatives. Since String does everything I need (only to chars, unfortunately) it feels like re-inventing the wheel.
Simplest definition of what I need is "a generic String".
Is there something like this in .NET or written for .NET?
If not, some guidelines for creating one would be great.
Edit after answers and comments:
What I need is not a wrapper that will wrap a specified underlying, mutable collection and represent it as read-only. What I need is a truly immutable collection of T with methods to process sequences of T. Think IList<T>.IndexOf(T) for example, it gets the index of an item. Now think String.IndexOf(String) method, it (unlike the IndexOf(Char) method of String) gets the index of a sequence of chars and String has a lot of these kind of methods.
Now, why I don't use ReadOnlyCollection<T>: Apart from it doesn't support "(String-like) methods such as Contains(IEnumerable)", it also is not immutable. An example:
var array = new char[] { 'a', 'b', 'c', 'd', 'e' };
var str = new string(array);
// array[2] is 'c' and str[2] is also 'c'
// I can't do str[2] = 'f', but:
array[2] = 'f';
// Now, array[2] is 'f' but str[2] is still 'c'
There is no way (which is not a hack) to change the state of a string. Now, let's take a look at ReadOnlyCollection<T>:
var array = new int[] { 1, 2, 3, 4, 5 };
var col = new ReadOnlyCollection<int>(array);
// Here the col[2] is 3
// I can't do col[2] = 6, but:
array[2] = 6;
// Now the col[2] is 6 as well.
Edit due to request - What I currently use:
The collection (Foo<T>):
// Something I started like an hour ago. The only thing it does right now is to
// copy (not wrap) a specified enumerable and provide read-only access to it.
public sealed class Foo<T> : IList<T> where T: struct
{
private readonly T[] _Array;
public T this[int index] { get { return _Array[index]; } }
IList<T>.this[int index]
{
get { return this[index]; }
set { throw new NotSupportedException(); }
}
public Foo(IEnumerable<T> collection)
{
// Enumerable.ToArray() method copies the content of the specified array.
// Whetever happens to the "collection", value of "_Array" will stay the same.
_Array = collection.ToArray();
}
// Most of the methods of IList<T> are explicitly implemented. IsReadOnly
// returns true and the methods that cause a change in collection throw
// "NotSupportedException"s just like ReadOnlyCollection<T>.
// IEnumerable<T> implementation uses an iterator block.
}
The extension methods:
// Extensions I used to manipulate collections so far.
// These are the things I want to get rid of.
public static class FooHelpers
{
// I remove the bodies of these methods due to the confusion they have caused.
// How they work is irrelevant and I posted these because of a request.
public static bool Contains<T>(this IEnumerable<T> collection,
IList<T> pattern) { }
public static int IndexOf<T>(this IEnumerable<T> collection,
IList<T> pattern) { }
public static int LastIndexOf<T>(this IList<T> collection,
IList<T> pattern) { }
public static IEnumerable<int> IndicesOf<T>(this IEnumerable<T> collection,
IList<T> pattern) { }
public static IEnumerable<int> LastIndicesOf<T>(this IList<T> collection,
IList<T> pattern) { }
public static IEnumerable<T[]> Split(this IList<T> source,
IList<T> seperator) { }
public static bool StartsWith<T>(this IEnumerable<T> collection,
IList<T> pattern) { }
public static bool EndsWith<T>(this IList<T> collection,
IList<T> pattern) { }
public static IEnumerable<T> Take<T>(this IList<T> collection,
int startIndex,
int length) { }
public static IEnumerable<T> Take<T>(this IEnumerable<T> collection,
int startIndex,
int length) { }
public static IEnumerable<T> TakeAll<T>(this IList<T> collection,
int startIndex) { }
}
There appears to be 2 questions here:
1) Create an immutable collection
The short answer is No, there is no built in support for this.
the closest answer is really a ReadOnlyCollection, you could create a simple wrapper
public class ImmutableCollection<T> : ReadOnlyCollection<T> {
public ImmutableCollection(IEnumerable<T> source) : base(source.ToList()) {}
}
The ToList call in the constructor makes a copy of the source collection so you can modify the source collection
Failing that you will have to implement your own class, probably inheriting from IList<T> or IEnumerable<T> and provide your own get accessor.
Either way you will have to bear in mind that each T cannot be guaranteed to be immutable (even with structs as the struct could have a field member that is a reference object).
But as you would still have to copy a source collection to make your collection imutable you would still be better off using the first example.
2) Provide extra functions to perform string like operations.
You would have to implement your own functions:
public bool Contains(IEnumerable<T> pattern) {
return IndicesOf(pattern).Any();
}
public int IndexOf(IEnumerable<T> pattern) {
return IndicesOf(pattern).Select(x=>(int?)x).FirstOrDefault() ?? -1;
}
public int LastIndexOf(IEnumerable<T> pattern) {
return IndicesOf(pattern).Select(x=>(int?)x).LastOrDefault()?? -1;
}
public IEnumerable<int> IndicesOf(IEnumerable <T> pattern) {
var count=pattern.Count();
return Enumerable.Range(0,this.Count()-count).Where(i=> pattern.SequenceEqual(internalTake(i,count)));
}
public IEnumerable<int> LastIndicesOf(IEnumerable<T> pattern) {
return IndicesOf(pattern).Reverse(); // Could Optimize
}
private IEnumerable<IEnumerable<T>> internalSplit(IEnumerable<T> seperator) {
var splitPoints=this.IndicesOf(seperator);
var length=seperator.Count();
var lastCount=0;
foreach(var point in splitPoints.Where(x=>!splitPoints.Any(y=>y<x && y+length>x))) {
yield return this.Take(lastCount,point-lastCount);
lastCount=point+length;
}
yield return this.TakeAll(lastCount);
}
public ImmutableCollection<T>[] Split(IEnumerable<T> seperator) {
return internalSplit(seperator).Select(x=>new ImmutableCollection<T>(x)).ToArray();
}
public bool StartsWith(IEnumerable<T> pattern) {
return pattern.SequenceEqual(this.Take(pattern.Count()));
}
public bool EndsWith(IEnumerable<T> pattern) {
return pattern.SequenceEqual(this.Skip(this.Count()-pattern.Count()));
}
private IEnumerable<T> internalTake(int startIndex, int length) {
var max=(length==-1) ? this.Count() : Math.Min(this.Count(),startIndex+length);
for (int i=startIndex;i<max;i++) yield return this[i];
}
public ImmutableCollection<T> Take(int startIndex, int length) {
return new ImmutableCollection<T>(internalTake(startIndex,length));
}
public ImmutableCollection<T> TakeAll(int startIndex) {
return new ImmutableCollection<T>(internalTake(startIndex,-1));
}
I think this is what you are looking for: List.AsReadOnly
http://msdn.microsoft.com/en-us/library/e78dcd75.aspx
If you want an efficient means of finding a subsequence your best best is probably going to be to write your own collection for the purpose. I'd suggest using a T[] combined with an int[] to store the hash codes of every value. One could then--to a significant degree--reduce the task of finding a sequence of T to finding a sequence of hash values. It may be possible to convert a sequence of N hash codes into a string of 3N characters using 3 characters to store each hash code, and then use string.Contains or a regex parser to perform the sequence lookup.
ReadOnlyCollection?
http://msdn.microsoft.com/en-us/library/ms132474.aspx

Categories

Resources