Linq Distinct仅在下一行匹配

时间:2015-10-11 22:42:40

标签: c# .net linq

我有一个包含以下信息的数据表:

365.00
370.00
369.59
365.00
365.00 -> match with previous item
365.00 -> match with previous item

我只需删除下一个匹配的项目,如下所示:

365.00
370.00
369.59
365.00

我试过了:

(from articlespricehistory in dt.AsEnumerable()
select new
{
   articlepricehistory_cost = articlespricehistory.Field<Double>("articlepricehistory_cost")
})
.DistinctBy(i => i.articlepricehistory_cost)
.ToList();

结果:

365.00
370.00
369.59

有什么想法吗?

6 个答案:

答案 0 :(得分:7)

另一种方法:

public static IEnumerable<T> MyDistinct<T>(this IEnumerable<T> items) 
{
    T previous = default(T);
    bool first = true;
    foreach(T item in items)
    {
        if (first || !Equals(previous, item)) 
        {
            first = false;
            previous = item;
            yield return item;
        }
    }
} 

或者,根据要求,使用选择器

public static IEnumerable<T> MyDistinct<T, U>(this IEnumerable<T> items, Func<T, U> selector) 
{
    U previous = default(U);
    bool first = true;
    foreach(T item in items)
    {
        U current = selector(item);
        if (first || !Equals(previous, current)) 
        {
            first = false;
            previous = current;
            yield return item;
        }
    }
} 

答案 1 :(得分:3)

这是一个适合你的LINQ解决方案

var list = (dt as Enumerable);

var numbers = list.TakeWhile((currentItem, index) => currentItem != list.ElementAtOrDefault(index - 1));

请记住,如果你将0作为第一个元素,它将从新列表中省略,因为ElementAtOrDefault将在while循环的第一次迭代中返回0(索引为-1),从而将表达式计算为false。简单的if语句可以帮助您避免这种情况。

答案 2 :(得分:2)

这是一个我没有尝试的想法

  • 对查询执行Skip(1)以生成第二个查询。
  • 现在向第二个查询追加任何不等于第一个查询中最后一个元素的元素,以生成第三个查询。
  • 现在zip将第一个和第三个查询连接在一起形成一组对;这是第四个查询。
  • 现在构造第五个查询,筛选出与第四个查询具有相同元素的对。
  • 最后,构造第六个查询,从第五个查询中选择每对的第一个元素。

第六个查询是您想要的数据集。

答案 3 :(得分:1)

您的查询中的问题是您使用.DistinctBy(),它将仅返回不同的结果。因此,如果365.00出现在任何地方,它将不会再次显示在返回的列表中。

var differentPreviousList = new List<double>();
var itemPriceList = dt.ToList();
differentPreviousList.Add(itemPriceList[0]);
for (var index = 1; index < itemPriceList.Count; index++)
{
    if (itemPriceList[index - 1] == itemPriceList[index]) continue;
    differentPriceList.Add(itemPriceList[index]);
}

答案 4 :(得分:0)

我认为您必须使用临时值来检查下一个值是否与当前值匹配。

double temporary = -1;  // temp value for checking
List<double> results = new List<double>(); // list to store results

(from articlespricehistory in dt.AsEnumerable()
 select new
 {
    articlepricehistory_cost = articlespricehistory.Field<Double>("articlepricehistory_cost")
 })
  .Select(a => a.articlepricehistory_cost)
  .ToList()
  .ForEach(cost => 
  {
      if (temporary != cost) { results.Add(cost); }
      temporary = cost;
  });

foreach (var result in results)
{
    Console.WriteLine(result);
}

ForEach方法等同于以下内容。

foreach (var cost in costs)
{
    if (temporary != cost)
    {
        results.Add(cost);
        Console.WriteLine(cost);
    }
    temporary = cost;
}

答案 5 :(得分:0)

它可能不是一个优雅的解决方案,但我只是解析一个简单的查询......这是怎么回事。

  1. 运行lambda查询以获取所有原始结果,而不尝试过滤掉DistinctBy。
  2. 创建最初查询类型的单个查询结果的对象。
  3. 初始化foreach解析结果的新列表。
  4. 为每个结果执行每个循环。
  5. 第一个if部分应该是if(上面的循环对象为空)。
  6. IF为true将项目添加到列表
  7. 如果检查项目的值是否与上次迭代相同,则为ELSE。
  8. 将foreach迭代对象存储到循环之前声明的对象。
  9. 冲洗并重复,结果是循环中连续发现的重复对象不会存储在列表中,从而产生你想要的东西。