Can I use LINQ to retrieve only “on change” values?

前端 未结 5 816
死守一世寂寞
死守一世寂寞 2021-01-22 20:36

What I\'d like to be able to do is construct a LINQ query that retrieved me a few values from some DataRows when one of the fields changes. Here\'s a contrived example to illus

5条回答
  •  北恋
    北恋 (楼主)
    2021-01-22 21:19

    Here is one more general thought that may be intereting. It's more complicated than what @tvanfosson posted, but in a way, it's more elegant I think :-). The operation you want to do is to group your observations using the first field, but you want to start a new group each time the value changes. Then you want to select the first element of each group.

    This sounds almost like LINQ's group by but it is a bit different, so you can't really use standard group by. However, you can write your own version (that's the wonder of LINQ!). You can either write your own extension method (e.g. GroupByMoving) or you can write extension method that changes the type from IEnumerable to some your interface and then define GroupBy for this interface. The resulting query will look like this:

    var weatherStuff = 
      from row in ds.Tables[0].AsEnumerable().AsMoving()
      group row by row.Field("Observation") into g
      select g.First();
    

    The only thing that remains is to define AsMoving and implement GroupBy. This is a bit of work, but it is quite generally useful thing and it can be used to solve other problems too, so it may be worth doing it :-). The summary of my post is that the great thing about LINQ is that you can customize how the operators behave to get quite elegant code.

    I haven't tested it, but the implementation should look like this:

    // Interface & simple implementation so that we can change GroupBy
    interface IMoving : IEnumerable { }
    class WrappedMoving : IMoving {
      public IEnumerable Wrapped { get; set; }
      public IEnumerator GetEnumerator() { 
        return Wrapped.GetEnumerator(); 
      }
      public IEnumerator GetEnumerator() { 
        return ((IEnumerable)Wrapped).GetEnumerator(); 
      }
    }
    
    // Important bits:
    static class MovingExtensions { 
      public static IMoving AsMoving(this IEnumerable e) {
        return new WrappedMoving { Wrapped = e };
      }
    
      // This is (an ugly & imperative) implementation of the 
      // group by as described earlier (you can probably implement it
      // more nicely using other LINQ methods)
      public static IEnumerable> GroupBy(this IEnumerable source, 
           Func keySelector) {
        List elementsSoFar = new List();
        IEnumerator en = source.GetEnumerator();
        if (en.MoveNext()) {
          K lastKey = keySelector(en.Current);
          do { 
            K newKey = keySelector(en.Current);
            if (newKey != lastKey) { 
              yield return elementsSoFar;
              elementsSoFar = new List();
            }
            elementsSoFar.Add(en.Current);
          } while (en.MoveNext());
          yield return elementsSoFar;
        }
      }
    

提交回复
热议问题