1

我有一个这个列表:

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),我想根据其名称选择对象。(参数提供的名称)

谢谢

4

5 回答 5

2

看起来你真的在追求类似的东西:

Dictionary<int, List<myobject>> myDataStructure;

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

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

于 2012-08-29T02:44:35.190 回答
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列表对此进行了测试,它在 106 毫秒内产生了结果。对于大多数情况,这应该足够快。

于 2012-08-29T03:18:00.603 回答
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
于 2012-08-29T03:14:52.140 回答
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);
}

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

于 2012-08-29T02:51:01.797 回答
0

如果保证 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      
}
于 2012-08-29T03:55:11.237 回答