linq datatable查找值发生的范围

时间:2013-11-27 21:33:14

标签: c# linq

我有一个像这样的数据表:

          Id Name State
          1  xx   CA 
          2  xx   NY
          3  xx   NY
          4  xx   NY
          5  xx   NY
          6  xx   CA
          7  xx   CA
          8  xx   NY
          9  xx   NY

我想知道是否有一个linq语句,我可以创建,在这种情况下,我返回值的范围(开始和结束),在这种情况下是一个状态。 例如Linq query = where(state ==“NY”)并返回2,5和7,9的出现

2 个答案:

答案 0 :(得分:1)

您可以使用此扩展程序对连续元素进行分组:

var result = dt.AsEnumerable()
    .GroupAdjacent(r => r.Field<string>("State"))
    .Where(g => g.Key == "NY")
    .Select(g => new{ Min=g.Min(r => r.Field<int>("Id")), Max=g.Max(r => r.Field<int>("Id")) })
    .ToList();

foreach (var x in result)
    Console.WriteLine("Min={0} Max={1}", x.Min, x.Max);   
// Min=2 Max=5
// Min=8 Max=9

这是扩展名:

public static IEnumerable<IGrouping<TKey, TSource>> GroupAdjacent<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector)
{
    TKey last = default(TKey);
    bool haveLast = false;
    List<TSource> list = new List<TSource>();
    foreach (TSource s in source)
    {
        TKey k = keySelector(s);
        if (haveLast)
        {
            if (!k.Equals(last))
            {
                yield return new GroupOfAdjacent<TSource, TKey>(list, last);
                list = new List<TSource>();
                list.Add(s);
                last = k;
            }
            else
            {
                list.Add(s);
                last = k;
            }
        }
        else
        {
            list.Add(s);
            last = k;
            haveLast = true;
        }
    }
    if (haveLast)
        yield return new GroupOfAdjacent<TSource, TKey>(list, last);
}

public class GroupOfAdjacent<TSource, TKey> : IEnumerable<TSource>, IGrouping<TKey, TSource>
{
    public TKey Key { get; set; }
    private List<TSource> GroupList { get; set; }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return ((System.Collections.Generic.IEnumerable<TSource>)this).GetEnumerator();
    }
    System.Collections.Generic.IEnumerator<TSource> System.Collections.Generic.IEnumerable<TSource>.GetEnumerator()
    {
        foreach (var s in GroupList)
            yield return s;
    }
    public GroupOfAdjacent(List<TSource> source, TKey key)
    {
        GroupList = source;
        Key = key;
    }
}

编辑:“我很抱歉,而不是使用id可以使用数据表的行索引”

是的,您可以使用投射索引的Select重载:

var result = dt.AsEnumerable()
    .Select((r, index) => new{ Row=r, Index=index })
    .GroupAdjacent(x => x.Row.Field<string>("State"))
    .Where(g => g.Key=="NY")
    .Select(g => new{ Min=g.Min(x => x.Index), Max=g.Max(x => x.Index) })
    .ToList();

答案 1 :(得分:0)

按照this answer中提出的逻辑,我想出了一些代码,可以帮到你:

注意为了时间的缘故,我创建了一个包含3个属性的类的列表,但是从DataTable中提取它应该几乎相同....

var newlist1 = (MyList.Where(li => li.State == "NY")
               .OrderBy(li => li.Id)
               .Select((li, idx) => new {itm = li, val = li.Id - idx})
               .GroupBy(nw => nw.val)
               .Select(g => new { Min = g.Min(nw => nw.itm.Id), 
                                  Max = g.Max(nw => nw.itm.Id)})
                ).ToList();

在排序结果之后,使这项工作的部分是val子句中的GroupBy - 实际上,由于数据是有序的,我们正在减去有序中每个元素的索引来自id的列表 - 所有顺序的元素将获得相同的val,因此将属于同一组。您需要做的就是,对于每个组,获得最大id和最小id,您就完成了。

希望这可以为您提供所需的信息。