tags:

views:

61

answers:

3

I am looking for some efficient way (in .NET), how to find if there is a sequence of bytes in some list of bytes and if there is any, index where the first starts.

For example let's say I have:

var sequence = new List<byte> { 5, 10, 2 };
var listOne = new List<byte> { 1, 3, 10, 5, 10, 2, 8, 9 };
var listTwo = new List<byte> { 1, 3, 10, 5, 2, 10, 8, 9 };

and the result should be that my sequence is on index 3 in the listOne and on index -1 (ie. it is not there) in the listTwo.

Of course I can loop through the list int by int and from every index and search if following numbers matches my sequence, but is there some more efficient way (for example using extension methods)?

A: 

I would suggest converting each List<int> to a String and then searching using the String.IndexOf(sequence) to determine where or if the sequence is present.

ChrisBD
Mmh I really doubt this will increase efficiency, because you have to create strings from lists (with more memory usage and more computation). For sure it will make things easier, because you don't need to write the code for searching the sub-string.
digEmAll
I am also worried about efficiency. But it would definitely shorter and maybe readable.
Lukáš Rubeš
If You create a extension method and describe it it will also by short and readable in place of usage.
Vash
I've created one in my answer
digEmAll
+2  A: 

This is essentially the same problem as substring searching (indeed, a list where order is significant is a generalisation of "string").

Luckily computer science has considered this problem frequently for a long time, so you get to stand on the shoulders of giants.

Take a look at the literature. Some reasonable starting points are:

http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm

http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm

http://en.wikipedia.org/wiki/Rabin-karp

Even just the pseudocode in the wikipedia articles is enough to port to C# quite easily. Look at the descriptions of performance in different cases and decide which cases are most likely to be encountered by your code. (I'm thinking the first from what you say about the search-key list being short).

Jon Hanna
Thank you for the links, I am just wondering, if there is any method implemented in .NET using some of these algorithms, to save my time, before implementing them myself.
Lukáš Rubeš
It's quite likely that `System.String.IndexOf` implements one of them! That you're applying the same algorithm to a datatype it isn't as often used for reduces your chances of finding an impl. I'm sure there's one out there somewhere, but finding it is a different matter.
Jon Hanna
A: 

I think the cleanest way is create a generic extension method like this:

public static int SubListIndex<T>(this IList<T> list, int start, IList<T> sublist)
{
    for (int listIndex = start; listIndex < list.Count - sublist.Count + 1; listIndex++)
    {
        int count = 0;
        while (count < sublist.Count && sublist[count].Equals(list[listIndex + count]))
            count++;
        if (count == sublist.Count)
            return listIndex;
    }
    return -1;
}

to call in this way:

var indexOne = listOne.SubListIndex(0, sequence);
var indexTwo = listTwo.SubListIndex(0, sequence);

P.S. you can also start from a given index, if you need to search for more sublists occurrences

digEmAll
That is exactly what I am doing now. But as Jon Hanna stated, there are more efficient ways for subset searching. I just want to know if I am not missing something in .NET.
Lukáš Rubeš
IMO those algorithms are not easily applicable to non-char strings. For example boyer-moore requires an array of alphabeth size and for Int32 alphabeth size is 2^32. Rabin-karp uses hashing that for non real strings could be quite difficult to implement. Probably the only really usable is Knuth–Morris–Pratt I guess but I don't think would be so faster...
digEmAll