2011-10-01 135 views
-2

如果序列中两个或多个元素在列表中具有相同属性,我想识别并提取元素。 例如 我有一个列表 有一个名为IsValid的 现在我想确定是否在序列中的两个或多个文档具有的IsValid ==文档属性真正 假设结构确定序列中两个或多个元素是否具有相同属性

IsValid = false 
IsValid = true 
IsValid = true 
IsValid = false 
IsValid = true 
IsValid = false 

我的查询应该只返回元素2和3,因为只有这两个顺序,并且ISvalid = true 我该如何实现它?

回答

0

您只需检查当前项目是否有效,以及上一个项目是否在同一时间有效。这将捕获大多数情况,但是如果尚未存储之前需要确保保留之前的项目。

类似下面的代码应该做的。请注意,它是从内存写入的,未经测试,而我不是最有效的方法。

public List<Document> GetConsecutiveTrueDocs(List<Document> list) 
{ 
    var result = new List<Document>(); 

    if(list.Count < 2) 
     return result; 

    for(int i = 1; i < list.Count; i++) 
    { 
     if(list[i].IsValid && list[i-1].IsValid) 
     { 
      if(!result.Contains(list[i-1])) 
       result.Add(list[i-1]); 

      result.Add(list[i]); 
     } 
    } 

    return result; 
} 
1

你可以写一个简单的LINQ扩展方法:

public static IEnumerable<IEnumerable<TSource>> 
    ContinuouslyEqualSubSequences<TSource, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TResult> func 
) { 
    var e = source.GetEnumerator(); 
    var currentSequence = default(List<TSource>); 
    var resultOfCurrentSequence = default(TResult); 
    if (e.MoveNext()) { 
     currentSequence = new List<TSource>() { e.Current }; 
     resultOfCurrentSequence = func(e.Current); 
    } 
    while (e.MoveNext()) { 
     var currentResult = func(e.Current); 
     if(Object.Equals(resultOfCurrentSequence, currentResult)) { 
      currentSequence.Add(e.Current); 
     } 
     else { 
      if(currentSequence.Count > 1) { 
       yield return currentSequence; 
      } 
      currentSequence = new List<TSource>() { e.Current }; 
      resultOfCurrentSequence = currentResult; 
      } 
     } 

     if (currentSequence.Count > 1) { 
      yield return currentSequence; 
     } 
    } 

var sequence = new { 3, 4, 7, 8, 9, 2, 4, 6, 0, 1, 1, 17, 2, 3, 2, 20 }; 
var subsequences = sequence.ContinuouslyEqualSubSequences(x => x % 2); 

我找回序列

2 4 6 0 
1 1 17 
2 20 

如预期,因为我们正在寻找这里为奇数o的连续子序列r偶数。

+0

哇。你的“简单”的定义显然与我的完全不同! – Gabe

+0

不要将长度与非简单混为一谈。这个算法*很简单。从序列中读取,跟踪当前的“投影”(我称它为resultOfCurrentSequence)。对于你遇到的相同投影的每个后续项目,将它添加到当前的子序列(我称它为“currentSequence”)。当遇到不同的东西时,如果长度超过一个,则产生当前的子序列,开始一个新的子序列并用新的投影替换旧的投影。如果到达序列的末尾,并且当前子序列的长度不止一个,则将其退回。 – jason

+0

我不是说你的*算法不简单,只是代码不是(我不是说你的代码有什么问题)。在22行中,它包含了对构造函数,方法和属性的14次调用,加上4个'if's和'while' - 这就忽略了缺少'using'来处理枚举数。而且,返回一系列序列并不像返回一个平坦序列那么简单。我的解决方案缩短了几行,没有构造函数/方法/属性调用,但它仍然不是我认为的“简单”。 – Gabe

0

下面是一个相对简单的扩展方法,它的来源序列,并告诉任何两个元素是否被视为相等的功能,并返回元素的一个序列:

public static IEnumerable<T> Consecutives<T>(this IEnumerable<T> source, 
              Func<T, T, bool> equals) 
{ 
    T last = default(T); 
    bool first = true; 
    bool returnedLast = false; 
    foreach (T current in source) 
    { 
     if (!first && equals(current, last)) 
     { 
      if (!returnedLast) 
       yield return last; 
      returnedLast = true; 
      yield return current; 
     } 
     else 
      returnedLast = false; 
     first = false; 
     last = current; 
    } 
} 

如果用

尝试
var sequence = new[] { 3, 4, 7, 8, 9, 2, 4, 6, 0, 1, 1, 17, 2, 3, 2, 20 }; 
var subsequences = sequence.Consecutives((x, y) => x % 2 == y % 2); 

你将得到: 2 4 6 0 1 1 17 2 20

如果你的序列不具有任何重复,T他雷蒙德的解决方案的扩展是效率低下,而且很简单:

public static IEnumerable<T> Consecutives<T>(this IEnumerable<T> source, 
              Func<T, T, bool> equals) 
{ 
    return source.Zip(source.Skip(1), (x, y) => new[] { x, y }) 
       .Where(d => equals(d[0], d[1])) 
       .SelectMany(d => d) 
       .Distinct(); 
} 
0

这可以通过自身的偏移版本荏苒序列减少到一个班轮。

public static IEnumerable<Tuple<TSource,TSource>> 
    Consecutives<TSource>(this IEnumerable<TSource> source, 
          Func<TSource, TSource, bool> equals) 
{ 
    return source.Zip(source.Skip(1), (x, y) => Tuple.Create(x,y)) 
       .Where(d => equals(d.Item1, d.Item2)); 
} 
+0

这听起来像OP想要一个'IEnumerable '作为结果,并且不清楚如何从你的函数的'IEnumerable >'得到它。 – Gabe

+0

如果连续有三个真实的项目,OP的要求是不明确的。他们想要(2,3,3,4)还是只需要(2,3,4)?对于前者,做一个SelectMany。对于后者,添加一个唯一。 –

+0

好的,但'Tuple'上的'SelectMany'没有任何意义。也许你想要一个数组? – Gabe

相关问题