基于两个属性从列表中选择不同值的最快方法

时间:2012-08-29 02:37:23

标签: c# linq list select distinct

我有一个这个清单:

List<myobject> list= new List<myobject>();

list.Add(new myobject{name="n1",recordNumber=1}); 
list.Add(new myobject{name="n2",recordNumber=2}); 
list.Add(new myobject{name="n3",recordNumber=3});
list.Add(new myobject{name="n4",recordNumber=3});

我正在寻找基于recordNumber选择不同对象的最快方法,但如果有多个具有相同recordNumber的对象(此处为recordNumber = 3),我想在其名称上选择对象。(名称)由paramater提供)

感谢

5 个答案:

答案 0 :(得分:2)

看起来你真的喜欢这样的事情:

Dictionary<int, List<myobject>> myDataStructure;

这允许您通过记录号快速检索。如果带有该词典键的List<myobject>包含多个条目,则可以使用该名称选择正确的名称。

请注意,如果您的列表不是非常长,那么只扫描列表检查recordNumber和名称的O(n)检查可能足够快,在某种意义上,其他事情发生在您的程序可能会模糊列表查找成本。在过度优化查找时间之前考虑这种可能性。

答案 1 :(得分:2)

这是LINQ的做法:

Func<IEnumerable<myobject>, string, IEnumerable<myobject>> getDistinct =
    (ms, n) =>
        ms
            .ToLookup(x => x.recordNumber)
            .Select(xs => xs.Skip(1).Any()
                ? xs.Where(x => x.name == n).Take(1)
                : xs)
            .SelectMany(x => x)
            .ToArray();

我刚用1,000,000随机创建的myobject列表测试了它,它产生的结果是106ms。对于大多数情况来说,这应该足够快。

答案 2 :(得分:1)

您在寻找

吗?
class Program
    {
        static void Main(string[] args)
        {
            List<myobject> list = new List<myobject>();

            list.Add(new myobject { name = "n1", recordNumber = 1 });
            list.Add(new myobject { name = "n2", recordNumber = 2 });
            list.Add(new myobject { name = "n3", recordNumber = 3 });
            list.Add(new myobject { name = "n4", recordNumber = 3 });

            //Generates Row Number on the fly
            var withRowNumbers = list 
                    .Select((x, index) => new 
                            {
                                Name = x.name,
                                RecordNumber = x.recordNumber,
                                RowNumber = index + 1
                            }).ToList();

            //Generates Row Number with Partition by clause
            var withRowNumbersPartitionBy = withRowNumbers
                    .OrderBy(x => x.RowNumber)
                    .GroupBy(x => x.RecordNumber)
                    .Select(g => new { g, count = g.Count() })
                    .SelectMany(t => t.g.Select(b => b)
                    .Zip(Enumerable.Range(1, t.count), (j, i) => new { Rn = i, j.RecordNumber, j.Name}))
                    .Where(i=>i.Rn == 1)
                    .ToList();
            //print the result
            withRowNumbersPartitionBy.ToList().ForEach(i => Console.WriteLine("Name =  {0}   RecordNumber = {1}", i.Name, i.RecordNumber));

            Console.ReadKey();
        }
    }

    class myobject
    {
        public int recordNumber { get; set; }
        public string name { get; set; }
    }

<强>结果:

Name =  n1   RecordNumber = 1
Name =  n2   RecordNumber = 2
Name =  n3   RecordNumber = 3

答案 3 :(得分:0)

你在寻找一种方法吗?

List<myobject> list= new List<myobject>();

list.Add(new myobject{name="n1",recordNumber=1}); 
list.Add(new myobject{name="n2",recordNumber=2}); 
list.Add(new myobject{name="n3",recordNumber=3});
list.Add(new myobject{name="n4",recordNumber=3});

public myobject Find(int recordNumber, string name)
{
    var matches = list.Where(l => l.recordNumber == recordNumber);

    if (matches.Count() == 1)
        return matches.Single();

    else return matches.Single(m => m.name == name);
}

这将 - 当然 - 如果有多个匹配或零匹配则中断。您需要编写自己的边缘案例和错误处理!

答案 4 :(得分:0)

如果name和recordNumber组合保证唯一,那么您始终可以使用Hashset

然后,您可以使用RecordNumber和Name通过使用here描述的方法生成HashCode。

class myobject 
{

     //override GetHashCode
     public override int GetHashCode()
     {
        unchecked // Overflow is fine, just wrap
        {
           int hash = 17;
           // Suitable nullity checks etc, of course :)
           hash = hash * 23 + recordNumber.GetHashCode();
           hash = hash * 23 + name.GetHashCode();
           return hash;
         }
     }
     //override Equals      
}