【问题标题】:Looping through a list to find an object with the largest number efficiently!循环遍历列表以有效地找到数量最多的对象!
【发布时间】:2011-04-09 23:15:42
【问题描述】:

使用 c# 我有一个列表,这些对象都有一个浮动质量,在创建对象时是随机的。

循环遍历列表并找到质量最大的对象的最有效方法是什么?

【问题讨论】:

  • 这取决于您想要访问此信息的次数。这个的用例是什么?一旦脱落?你会想找出最低的吗?
  • 是的,我稍后也会找到最低的
  • 时间或空间效率?
  • 有趣的是,您的问题将其关闭为一个可能的答案:“循环遍历列表的最有效方法”是,tadaaaa,遍历列表我>

标签: c# algorithm list xna physics


【解决方案1】:

使用简单列表最有效的方法是简单的线性时间搜索,如

SomeObject winner;
float maxMass = 0.0f; // Assuming all masses are at least zero!
foreach(SomeObject o in objects) {
    if(o.mass > maxMass) {
        maxMass = o.mass;
        winner = o;
    }
}

如果您打算定期执行此操作,那么按照质量排序的顺序存储您的对象和/或使用更合适的存储容器可能会有所帮助。

【讨论】:

    【解决方案2】:

    听起来像是morelinq 中 MaxBy/MinBy 运算符的完美候选者。您可以按如下方式使用它:

    objects.MaxBy(obj=>obj.Mass)
    

    【讨论】:

    • @Mike:不,它没有。内置的 LINQ 堆栈 Max/Min 运算符将只返回相应的 value,而不是它所在的 object
    • @Mike:这仅适用于原始类型,而不是如果您正在寻找的最大值是属性,在@spender 的示例中Mass
    • @Mike:您可能会将MaxByMax 混淆
    【解决方案3】:

    实施 IComparable 将使事情变得简单且易于维护。我提供了一个例子。希望这可以帮助。 我不确定这是否比循环更有效。我知道有时使用 linq 在第一次调用时会稍微降低性能。

    但在很多时候,可维护代码的得分肯定比轻微的性能提升要高。有人可以提供有关 PARALLEL 执行与使用 AsParallel() 循环的性能的更多详细信息。

    class Program
    {
        delegate int Del();
        static void Main(string[] args)
        {
            List<MyClass> connections = new List<MyClass>();
            connections.Add(new MyClass() { name = "a", mass = 5.001f });
            connections.Add(new MyClass() { name = "c", mass = 4.999f }); 
            connections.Add(new MyClass() { name = "b", mass = 4.2f });
            connections.Add(new MyClass() { name = "a", mass = 4.99f });
    
            MyClass maxConnection = connections.AsParallel().Max();
            Console.WriteLine("{0} {1} ", maxConnection.name, maxConnection.mass);
            Console.ReadLine();
        }
    
        class MyClass : IComparable
        {
            public string name { get; set; }
            public float mass { get; set; }
    
            public int CompareTo(object obj)
            {
                return (int)(mass - ((MyClass)obj).mass);
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      最简单和最有效的解决方案(假设重复查询)是按大小对列表进行排序。

      private int SortByMass(ObjectWithMass left,ObjectWithMass right)
      {
        return left.Mass.CompareTo(right.Mass);
      }    
      List<ObjectWithMass> myList = MyFunctionToPopulateTheList();
      myList.sort(SortByMass);
      

      列表排序后,第一个元素是最小的,最后一个是最大的。 如果你想从大到小,你可以使用myList.Reverse()

      这个运行在o(nlog(n))中进行排序,然后找到最大的对象是myList[myList.Count -1]。对于 .net 列表,这是 o(1)(它们实际上是下面的数组)

      【讨论】:

        【解决方案5】:

        如果您愿意用一点空间来换取时间,那么在其中一个实例构造函数中,有如下内容

        public Foo(Foo min, Foo max)
        {
           min = min ?? new Foo();  
           max = max ?? new Foo();
        
           if(max.mass < this.mass)
            max = this;
        
           if(min > this.mass)
            min = this;
        }
        

        在创建对象时,让调用方法传递这些参数。

        Foo min, max = null;
        
        //Create a bunch of Foo objects
        
        var Foos = from n in Enumerable.Range(0, 10000) select new Foo(min, max);
        

        【讨论】:

        • 如果您要这样做,只需将其插入 OrderedSet 并传递一个按质量进行比较的比较器;这样你就会得到答案(.First() 和 .Last())等等
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-22
        • 2013-05-29
        • 1970-01-01
        • 2021-03-24
        • 2021-12-14
        • 2015-06-27
        相关资源
        最近更新 更多