繁体   English   中英

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

[英]Fastest way to select distinct values from list based on two properties

我有一个清单:

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提供) )

谢谢

看起来您确实是在追求类似的东西:

Dictionary<int, List<myobject>> myDataStructure;

这样您就可以按记录号快速检索。 如果具有该字典键的List<myobject>包含多个条目,则可以使用该名称选择正确的条目。

请注意,如果列表不是很长,那么仅扫描列表以检查recordNumber和name的O(n)检查可能足够快 ,因为程序中发生的其他事情可能会掩盖列表查找的费用。 在过度优化查找时间之前,请考虑这种可能性。

这是执行此操作的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内产生了结果。 对于大多数情况,这应该足够快。

你在找吗

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

您是否正在寻找一种方法来做到这一点?

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);
}

如果有多个匹配项或零个匹配项,这当然会中断。 您需要编写自己的优势案例和错误处理方法!

如果名称和recordNumber的组合保证是唯一的,则可以始终使用Hashset

然后,可以通过使用此处描述的方法,使用RecordNumber和Name生成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      
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM