提问人:Yidi 提问时间:10/20/2023 最后编辑:Dmitry BychenkoYidi 更新时间:10/20/2023 访问量:54
检查列表是否连续出现在任何给定列表中
Check if a list appear consecutively in any of the given lists
问:
我有一个主要列表:
public List<List<string>> validOrders = new List<List<string>>
{
new List<string> { "01", "02", "03", "04", "05", "06" },
new List<string> { "02", "03", "01", "04", "05", "06" },
new List<string> { "02", "03", "04", "01", "05", "06" },
};
然后我还有另一个列表:
public List<string> childObjectsPrefix = new List<string>();
现在,我想将childObjectsPrefix与validOrders列表进行比较,并检查起始集是否连续出现在任何validOrders列表中。
假设我的用例是这样的:
List<string> test1 = new List<string> { "01", "04" }; // False
List<string> test2 = new List<string> { "01", "02" }; // True
List<string> test3 = new List<string> { "02", "01" }; // False
List<string> test4 = new List<string> { "02", "03", "01" }; // True
List<string> test5 = new List<string> { "02", "03", "05" }; // False
我知道如何检查列表的子集,这相当简单,但这有点棘手。
答:
2赞
Den
10/20/2023
#1
您可以连续执行此操作:
public static bool IsConsecutiveSubset(List<List<string>> validOrders, List<string> childObjectsPrefix)
{
foreach (var validOrder in validOrders)
{
if (validOrder.Count < childObjectsPrefix.Count)
continue; // Skip if the sublist is shorter than childObjectsPrefix
for (int i = 0; i <= validOrder.Count - childObjectsPrefix.Count; i++)
{
if (childObjectsPrefix.SequenceEqual(validOrder.GetRange(i, childObjectsPrefix.Count)))
return true; // Found a match
}
}
return false; // No consecutive subset found
}
开始代码如下:
public static bool StartsWithPrefix(List<List<string>> validOrders, List<string> childObjectsPrefix)
{
foreach (var validOrder in validOrders)
{
if (validOrder.Count < childObjectsPrefix.Count)
continue; // Skip if the sublist is shorter than childObjectsPrefix
if (validOrder.Take(childObjectsPrefix.Count).SequenceEqual(childObjectsPrefix))
return true; // Found a match
}
return false; // No valid start found
}
评论
0赞
Yidi
10/20/2023
感谢您的回答,但不幸的是它输出 { “01”, “04” } 为 true。这是错误的,因为列表不是以这些字符串开头的。
0赞
Den
10/20/2023
开始不是连续的......然后我编辑响应
0赞
Yidi
10/20/2023
是的,对不起,我的意思是从开始。
0赞
Yidi
10/20/2023
谢谢你,这奏效了!:)感谢您的快速解决方案。
1赞
Dmitry Bychenko
10/20/2023
#2
在一般情况下(任意类型,长集合),我们可以使用 Knuth Morris Pratt 算法,请注意,如果列表中的项目被视为“字母” 我们在“strings”中寻找一个“substring”。
即我们可以构建 KMP 数组:
private static int[] KmpArray<T>(IEnumerable<T> sequence,
IEqualityComparer<T> comparer = default) {
if (sequence is null)
throw new ArgumentNullException(nameof(sequence));
comparer ??= EqualityComparer<T>.Default;
IReadOnlyList<T> pattern = sequence as IReadOnlyList<T> ?? sequence.ToList();
int[] result = new int[pattern.Count];
int length = 0;
int current = 1;
while (current < pattern.Count)
if (comparer.Equals(pattern[current], pattern[length]))
result[current++] = ++length;
else if (length != 0)
length = result[length - 1];
else
result[current++] = length;
return result;
}
然后使用它
public static IEnumerable<int> IndexesOf<T>(IEnumerable<T> source,
IEnumerable<T> pattern,
IEqualityComparer<T> comparer = default) {
if (source is null)
throw new ArgumentNullException(nameof(source));
if (pattern is null)
throw new ArgumentNullException(nameof(pattern));
IReadOnlyList<T> pat = pattern as IReadOnlyList<T> ?? pattern.ToList();
if (pat.Count == 0)
yield break;
int[] lps = KmpArray(pat);
comparer ??= EqualityComparer<T>.Default;
int i = 0;
int j = 0;
using var en = source.GetEnumerator();
for (bool agenda = en.MoveNext(); agenda;) {
if (comparer.Equals(pat[j], en.Current)) {
i += 1;
j += 1;
agenda = en.MoveNext();
}
if (j == pat.Count) {
yield return i - j;
j = lps[j - 1];
}
else if (agenda && !comparer.Equals(pat[j], en.Current)) {
if (j != 0)
j = lps[j - 1];
else {
i += 1;
agenda = en.MoveNext();
}
}
}
}
完成这些后,我们应该放一个简单的 Linq:
var order = new List<string> { "01", "02" };
bool result = validOrders.Any(item => IndexesOf(item, order).Any());
评论
"020301040506".Contains("0104")
= true,和 = false,正如你所期望的那样,对吧?Ofc,只有当您对字符串可能包含的内容有一些先验知识时,这种方法才有可能。"010203040506".Contains("0104")