How to get position of a sublist within another list?

4

I have a list of bytes and I need to check if it contains a sub-list of bytes in a specific order.

How can I make this check by getting the position of the sub-list in a simple way, using the Linq or the List features, that is, without having to do for checking position the position.

Exemplifying:

List<byte> bytes = new List<byte> { 10, 20, 30, 40, 50, 60, 70, 80  };
List<byte> pattern = new List<byte> { 30, 40, 50 };

int indiceInicioSublista = ???
    
asked by anonymous 25.04.2014 / 21:23

2 answers

2

You can nest two loops to do this: for each valid position in the main list, check that each item in the list being searched hits. If it reaches the end without finding, then it returns a negative value, indicating that it did not find it.

The LINQ version, equivalent is at the end of the answer.

public static int FindSubList<T>(IList<T> mainList, IList<T> subList)
{
    for (int it = 0; it <= mainList.Count - subList.Count; it++)
    {
        bool allEquals = true;
        for (int it2 = 0; it2 < subList.Count; it2++)
        {
            if (!mainList[it + it2].Equals(subList[it2]))
            {
                allEquals = false;
                break;
            }
        }

        if (allEquals)
            return it;
    }

    return -1;
}

Using LINQ would look like this, which is the equivalent of the above code:

public static int FindSubList<T>(IList<T> mainList, IList<T> subList)
{
    for (int it = 0; it <= mainList.Count - subList.Count; it++)
        if (!subList.Where((t, it2) => !mainList[it + it2].Equals(t)).Any())
            return it;

    return -1;
}

Another alternative using LINQ over IEnumerable , however this solution is slower than the one above:

public static int FindSubEnumerable<T>(IEnumerable<T> mainList, IEnumerable<T> subList)
{
    return
        Enumerable.Range(1, mainList.Count())
            .FirstOrDefault(it => mainList.Skip(it - 1).Take(subList.Count()).SequenceEqual(subList)) - 1;
}
    
25.04.2014 / 21:33
1

Get equal elements regardless of position.

List<byte> result = bytes.Where(e => pattern.Contains(e)).ToList<byte>();
IEnumerable<byte> result1 = bytes.Intersect(pattern);
IList<byte> result3 = bytes.Intersect(pattern).ToList<Byte>();

Return true, if bytes is within pattern , which have been converted to String.

bool retorno = String.Join("", bytes).Contains(string.Join("", pattern));

References

1 - Getting Started with LINQ in C #

2 - 101 LINQ Samples

    
25.04.2014 / 21:37