确定序列中的两个或多个元素是否具有相同的属性

时间:2011-10-01 03:45:10

标签: c#

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

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

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

4 个答案:

答案 0 :(得分: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

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

答案 1 :(得分: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;
}

答案 2 :(得分: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

如果您的序列没有重复,那么Raymond解决方案的扩展效率低下,但非常简单:

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();
}

答案 3 :(得分: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));
}