删除多次出现的列表元素

时间:2016-04-05 02:13:47

标签: c# linq list

发布了一个类似的问题,但我没有代表在该帖子中询问后续问题:(

该问题和解决方案是HERE

如果我的列表包含多次出现的项目,List.Distinct()将删除重复项,但原始文件仍会保留。如果我想删除多次出现的项目,包括原始项目,那么对ORIGINAL列表执行此操作的最有效方法是什么?

给定名为oneTime的List: { 4, 5, 7, 3, 5, 4, 2, 4 }

所需的输出将在oneTime中: { 7, 3, 2 }

感谢您的帮助!

---- @enigmativity的编辑和跟进问题,8月18日-----------------

这是我的脚本正在做的伪版本。它是在NinjaTrader中完成的,它运行在.NET3.5上。

我将附上代码应该做的一般概念,我会附上实际的脚本,但除非使用NinjaTrader,否则它可能没有用。

但实质上,有一个大的z循环。每一次,“LiTics”都会添加一系列数字。哪个我不想打扰。然后我将该列表传递给函数,并返回仅出现一次的值列表。然后,我希望每次都能看到这些数字。

它最初工作,但是在各种数据集上运行它,经过几次循环后,它开始报告多次出现的值。我不确定为什么呢?

for(int z=1; z<=10000; z +=1)//Runs many times 
{ 
    if (BarsInProgress ==0 &&CurrentBar-oBarTF1>0 &&startScript )   //Some Condition
    {
        for(double k=Low[0]; k<=High[0]; k +=TickSize)  
        {   
            LiTics.Add(k);  
            //Adds a series of numbers to this list each time through z loop
            //This is original that I do not want to disturb
        }

        LiTZ.Clear();  //Display list to show me results Clear before populating
        LiTZ=GetTZone(LiTics); //function created in thread(below)
                               //Passing the undisturbed list that is modified on every loop
        foreach (double prime in LiTZ) { Print(Times[0] +",  " +prime);  }
        //Printing to see results   
    }

}//End of bigger 'z' loop

//Function created to get values that appear ONLY once
public List<double> GetTZone(List<double> sequence) 
{  
    var result =
        sequence
            .GroupBy(x => x)
            .Where(x => !x.Skip(1).Any())
            .Select(x => x.Key)
            .ToList();
    return result;

}

打印输出的图片以及出错的地方:  http://i.stack.imgur.com/pXcdK.jpg

2 个答案:

答案 0 :(得分:4)

所以,如果你有一个新列表,那么这是最简单的方法:

var source = new List<int>() { 4, 5, 7, 3, 5, 4, 2, 4 };

var result =
    source
        .GroupBy(x => x)
        .Where(x => !x.Skip(1).Any())
        .Select(x => x.Key)
        .ToList();

这给出了:

{ 7, 3, 2 }

如果要从原始源中删除值,请执行以下操作:

var duplicates =
    new HashSet<int>(
        source
            .GroupBy(x => x)
            .Where(x => x.Skip(1).Any())
            .Select(x => x.Key));

source.RemoveAll(n => duplicates.Contains(n));

答案 1 :(得分:-1)

我有两个选项,一个使用HashSet和其他Linq

选项1:

使用HashSet,循环收集并插入(如果不存在)并删除它是否存在。

HashSet<int> hash = new HashSet<int>();

foreach(var number in list)
{
    if(!hash.Contains(number)) hash.Add(number);
    else hash.Remove(number);               
}
list = hash.ToList();

选项2:

简单Linq,对其计数为>1的元素和过滤器进行分组。

var list= list.GroupBy(g=>g)
    .Where(e=>e.Count()==1)
    .Select(g=>g.Key)
    .ToList();

使用HashSet而不是Linq性能增益,显而易见,Linq(在这种情况下)需要多次迭代,其中HashSet 1}}使用单次迭代并通过O(1)访问提供LookUp(用于添加/删除)。

Elapsed Time (Using Linq): 8808 Ticks
Elapsed Time (Using HashSet): 51 Ticks

工作Demo