我有一系列对象,我想迭代以最终识别某种类型的模式。目前我有一堆if语句检查表达式的标志。例如,我有if(!foundFirstObjectOfTypeA)的内容。一旦我找到了类型A的第一个对象,我就会将该标志设置为true,我们将不再执行该块并继续执行下一个块。我有几种类型的模式可以识别,因此它创建了一大块难以理解和丑陋的if语句。
有没有办法在没有评估foreach循环中的表达式的情况下查看/查看标识符?如果我可以按照if(identifer == ObjectA&& identifer.next == ObjectB)的方式做一些事情,那么它将使我的代码更具可读性和可理解性,而且我可以在不必设置标志的情况下进行处理。
如果没有直接的方法/方式,有人会有一些聪明的解决方法来模拟我想要的效果吗?
答案 0 :(得分:6)
使用for
循环来增加i
,然后只需查看object[i]
和object[i+1]
。你使用什么类型的收藏?一个列表?数组?所有foreach
循环都会隐藏计数器。如果我了解您的情况,那么使用foreach
循环而不是for
循环绝对是没有的理由。
这适用于任何列表和任何对象序列:
<强>功能:强>
public static bool ContainsSequence
(System.Collections.Generic.IList<object> list, params object[] seq)
{
for (int i = 0; i < list.Count() - seq.Count() + 1; i++)
{
int j;
for (j = 0; j < seq.Count(); j++)
{
if (list[i + j] != seq[j])
break;
}
if (j == seq.Count())
return true;
}
return false;
}
<强>用法:强>
private static void Main(string[] args)
{
var A = new object();
var B = new object();
var C = new object();
var D = new object();
var list = new[] {A, B, C, D};
Console.WriteLine(ContainsSequence(list, B, C, D));
Console.WriteLine(ContainsSequence(list, A, D, C, B, A, C));
Console.WriteLine(ContainsSequence(list, A, B));
}
<强>输出:强>
True
False
True
如果您知道要查找的对象数量(如果您只查找两个,它几乎是 Hamid Nazari的答案 - 可以使函数变得更简单 - 您只需需要在下面添加 AndrewS 的绑定检查。)
如果你想要序列开头的 index ,你可以将我的函数的返回类型更改为int并返回i
而不是true
(和返回-1
而不是false
。)
答案 1 :(得分:2)
我认为没有直接的支持,但你可以随时效仿。
例如(解决方案的一部分):
static IEnumerable<Peekable<T>> ToPeekable(this IEnumerable<T> stream)
{
T prev = <get first item, and move...>
foreach(T item in stream)
{
yield return new Peekable<T>(prev, item);
prev = item;
}
yield return new Peekable<T>(item, default(T));
}
更新:缺少部分
class Peekable<T>
{
public Peekable(T current, T next)
{
Current = current;
Next = next;
}
public T Current { get; private set; }
public T Next { get; private set; }
}
static class PeekableAdaptor
{
public static IEnumerable<Peekable<T>> ToPeekable<T>(this IEnumerable<T> stream)
{
var source = stream.GetEnumerator();
if (!source.MoveNext())
yield break;
T prev = source.Current;
while (source.MoveNext())
{
yield return new Peekable<T>(prev, source.Current);
prev = source.Current;
}
yield return new Peekable<T>(prev, default(T));
}
}
class Program
{
static void Main(string[] args)
{
foreach (var pair in Enumerable.Range(1, 10).ToPeekable())
{
Console.WriteLine(pair.Current, pair.Next);
}
}
}
答案 2 :(得分:0)
如果你使用for循环,你可以这样做。
for (int i = 0; i < list.Count - 1; i++)
if (list[i] == ObjectA && list[i + 1] == ObjectB)
; // Your code
答案 3 :(得分:0)
IEnumerable
是一个非常轻的forward-only
迭代器实现。如果您查看IEnumerator
interface,则只有三个成员:
作为解决方案,您可以手动迭代IEnumerable
或使用循环。
bool MoveNext()
void Reset()
object Current
因此,唯一的操作是前进,重置和检索当前项目。没有内置的能力来偷看接下来会发生什么。
bool someFlag = false;
IEnumerable<object> collection = new object[]{"string", true, 4, DateTime.Now};
using (var enumerator = collection.GetEnumerator()) {
while (true ) {
bool end = enumerator.MoveNext();
if (!end) {
if (enumerator.Current.GetType() == typeof(string)) {
end = enumerator.MoveNext();
if (!end && enumerator.Current.GetType() == typeof(bool))
someFlag = true;
}
}
if (end) break;
}
}
bool someFlag = false;
List<object> collection = new object[]{"string", true, 4, DateTime.Now};
int i = 0;
while (true ) {
bool end = i < collection.Count;
if (!end) {
if (collection[i] == typeof(string)) {
i++;
end = i < collection.Count;
if (!end && collection[i] == typeof(bool))
someFlag = true;
}
}
if (end) break;
}
}
答案 4 :(得分:0)
使用我对此question的回答,我想出了这种变体作为可能的解决方案。这适用于任何类型的集合;即使是那些无法编入索引的人。
foreach (var item in ForEachHelper.Wrap(collection))
{
Console.WriteLine("Position=" + item.Index.ToString());
Console.WriteLine("Current=" + item.Current.ToString());
if (item.HasNext)
{
Console.WriteLine("Next=" + item.Next.ToString());
}
}
以下是相关代码。
public static class ForEachHelper
{
public sealed class Item<T>
{
public int Index { get; set; }
public T Current { get; set; }
public T Next { get; set; }
public bool HasNext { get; set; }
}
public static IEnumerable<Item<T>> Wrap<T>(IEnumerable<T> enumerable)
{
IEnumerator<T> enumerator = enumerable.GetEnumerator();
try
{
var item = new Item<T>();
item.Index = 0;
item.Current = default(T);
item.Next = default(T);
item.HasNext = false;
if (enumerator.MoveNext())
{
item.Current = enumerator.Current;
if (enumerator.MoveNext())
{
item.Next = enumerator.Current;
item.HasNext = true;
}
while (item.HasNext)
{
var next = new Item<T>();
next.Index = item.Index + 1;
next.Current = item.Next;
next.Next = default(T);
if (enumerator.MoveNext())
{
next.Next = enumerator.Current;
next.HasNext = true;
}
var current = item;
item = next;
yield return current;
}
yield return item;
}
}
finally
{
enumerator.Dispose();
}
}
}