список, в котором порядок является существенным является обобщением понятия строки. Поэтому вы хотите использовать алгоритм подстроки.
Существует несколько возможностей, но Кнут-Моррис-Пратт - хороший выбор. Он имеет некоторые начальные накладные расходы Θ (m), где m - длина искомого искателя, а затем находит в Θ (n), где n - это расстояние до искомого искателя или длина всего списка, если его нет , Это бьет простой пункт за пунктом сравнения, который является Θ ((п-т + 1) м):
public static class ListSearching
{
public static bool Contains<T>(this IList<T> haystack, IList<T> needle)
{
return Contains(haystack, needle, null);
}
public static bool Contains<T>(this IList<T> haystack, IList<T> needle, IEqualityComparer<T> cmp)
{
return haystack.IndexOf(needle, cmp) != -1;
}
public static int IndexOf<T>(this IList<T> haystack, IList<T> needle)
{
return IndexOf(haystack, needle, null);
}
public static int IndexOf<T>(this IList<T> haystack, IList<T> needle, IEqualityComparer<T> cmp)
{
if(haystack == null || needle == null)
throw new ArgumentNullException();
int needleCount = needle.Count;
if(needleCount == 0)
return 0;//empty lists are everywhere!
if(cmp == null)
cmp = EqualityComparer<T>.Default;
int count = haystack.Count;
if(needleCount == 1)//can't beat just spinning through for it
{
T item = needle[0];
for(int idx = 0; idx != count; ++idx)
if(cmp.Equals(haystack[idx], item))
return idx;
return -1;
}
int m = 0;
int i = 0;
int[] table = KMPTable(needle, cmp);
while(m + i < count)
{
if(cmp.Equals(needle[i], haystack[m + i]))
{
if(i == needleCount - 1)
return m == needleCount ? -1 : m;//match -1 = failure to find conventional in .NET
++i;
}
else
{
m = m + i - table[i];
i = table[i] > -1 ? table[i] : 0;
}
}
return -1;
}
private static int[] KMPTable<T>(IList<T> sought, IEqualityComparer<T> cmp)
{
int[] table = new int[sought.Count];
int pos = 2;
int cnd = 0;
table[0] = -1;
table[1] = 0;
while(pos < table.Length)
if(cmp.Equals(sought[pos - 1], sought[cnd]))
table[pos++] = ++cnd;
else if(cnd > 0)
cnd = table[cnd];
else
table[pos++] = 0;
return table;
}
}
Тестирование это:
var list = new[]{ 1, 1, 2, 5, 8, 1, 9, 1, 2 };
Console.WriteLine(list.Contains(new[]{2,5,8,1,9})); // True
Console.WriteLine(list.Contains(new[]{1,2,5,8,1})); // True
Console.WriteLine(list.Contains(new[]{5,2,1})); // False
Console.WriteLine(list.Contains(new[]{1,2,5,1,8})); // False
Console.WriteLine(list.Contains(new[]{1,1,2})); // True
Console.WriteLine(list.Contains(new[]{1,1,1,2})); // False
, что это, по существу сопоставление с образцом, как в 'string.Contains (строка)'. –
Я использовал числа, чтобы упростить мою проблему (включая объекты). Я полагаю, что контекст моей проблемы омрачал этот очевидный факт. – 2c2c
Это также более очевидно, если вы когда-либо обобщали строку вне элементов, отличных от символов, до или без. После первого раза натолкнулся на это, другие случаи, которые являются обобщениями строк, выделяются. Во всяком случае, я бы сказал, что поеду с Кнутом-Моррисом-Праттом в соответствии с моим ответом, если у вас нет оснований использовать другой (например, Ахо-Корасик для поиска набора подписок одновременно) –