0

我和一个朋友正在编写一些软件(作为一个副项目)并且遇到了 ArrayLists 的问题。

我们将自定义对象的实例集合(包含一个 DateTime 和两个字符串)存储在一个 ArrayList 中。一旦我们将所有条目存储在 ArrayList 中,我们将按 DateTime 对它们进行排序。问题是,我们必须存储对象的 100,000 个实例,这意味着内置的排序方法需要很长时间——我们有一次将它计时了一个多小时。

排序的速度并不是什么大问题,但我只是想知道是否有比使用内置排序方法更好的方法来对 ArrayList 中的元素进行排序。虽然我猜不是,但基于内置的 .net 内容将得到高度优化这一事实。

注意:我们使用 ArrayLists 是因为我们选择使用中间件来根据 ArrayList 的内容生成 PDF 报告。我想,如果我们有机会移到 List<> 那么排序方法会更好。或者他们会?

编辑:

根据对源代码的要求,我会发布一些。但我不确定我能提供多少这并不明显。

public class DataObject : ICompareable
{
   private DateTime timeStamp;
   private string description;
   private string detail;

   public DataObject (DataTime inTimeStamp, string inDescription,
                      string inDetail)
   {
      this.timeStamp = inTimeStamp;
      this.description = inDescription;
      this.detail = inDetail;
   }

   int IComparable.CompareTo(object that)
   {
       DataObject myThat = (DataObject)that;
       return this._timestamp.CompareTo(myThat._timestamp);
   }
}

 // .... //

ArrayList dataList = new ArrayList();
for (int i = 0; i < database.Packets.Count; i++)
{
  dataList.Add(new DataObject(database.Packet(i).GetTimeStamp(),
               database.Packet(i).GetDescription(),
               database.Packet(i).GetDetail());
}

// ... same as the above, but for other data
// ... types (all parse to strings when pulled
// ... from the database

dataList.Sort();

大致就是这样。我们从 SQLCEME3.5 数据库中的多个位置提取数据(我们使用的是 .net 3.5,因此不能使用 LINQ),将它们放在对象的 ArrayList 中,并在管道的下方使用该对象 ArrayList。

我们希望从数据库中的多个位置获取所有记录(一些是数据包,一些是字符串(提示),一些是其他类型,全部解析为字符串)并按时间戳对它们进行排序。我们希望所有数据散布在一个数据包后面,然后是一些字符串值,然后是一些对象值,如果这是它们存储/生成的顺序。

我们对数据库具有只读访问权限,因此我认为使用数据库本身对它们进行排序不是一个好主意(甚至可能)。话虽如此,我对 SQL 真的很陌生——在这个项目之前从未使用过它。可以这样做吗?

4

2 回答 2

1

如果您的数据是时间戳,那么这是一个实现。

在 200 毫秒内对 100,000 行进行排序。
它必须做很多排序。
你的代码有问题。

namespace TimeStamp
{
    class Program
    {
        static void Main(string[] args)
        {
            string connString = "data source=... size=4096";
            ArrayList al = new ArrayList();
            using (SqlConnection sqlCon = new SqlConnection(connString))
            {            
                sqlCon.Open();
                SqlCommand sqlCmd = sqlCon.CreateCommand();
                sqlCmd.CommandText = "SELECT [timestamp], [value] FROM [TimeStmp] Order By [timestamp] desc";
                SqlDataReader rdr = sqlCmd.ExecuteReader();
                while (rdr.Read())
                {
                    // al.Add(new ValueWithTimeStamp(rdr.GetSqlBinary(0), rdr.GetString(1)));
                    for (int i = 0; i < 10000; i++)  al.Add(new ValueWithTimeStamp(rdr.GetSqlBinary(0), rdr.GetString(1)));
                    // table has 10 rows so this is 100,000 and the select is desc to is has to so a lot of sorting
                }
            }
            for (int i = 0; i < 10; i++) Debug.WriteLine(((ValueWithTimeStamp)al[i]).TimeStampUInt64.ToString());
            System.Diagnostics.Stopwatch sw = new Stopwatch();
            sw.Start();
            al.Sort();
            sw.Stop();
            for (int i = 0; i < 10; i++) Debug.WriteLine(((ValueWithTimeStamp)al[i]).TimeStampUInt64.ToString());
            Debug.WriteLine(sw.ElapsedMilliseconds.ToString());
        }
    }
    public struct ValueWithTimeStamp: IComparable
    {
        private UInt64 timeStampUInt64;
        private string value;
        public int CompareTo(object obj)
        {
            if (obj == null) return -1;
            if (!(obj is ValueWithTimeStamp)) return -1;
            ValueWithTimeStamp comp = (ValueWithTimeStamp)obj;
            return this.TimeStampUInt64.CompareTo(comp.TimeStampUInt64);
        }
        public UInt64 TimeStampUInt64 { get { return timeStampUInt64; } }
        public string Value { get { return value; } }
        public ValueWithTimeStamp(System.Data.SqlTypes.SqlBinary TimeStamp, string Value)
        {
            // using UInt64 for timeStampUInt64  as it implements CompareTo and is something you can read
            timeStampUInt64 = BitConverter.ToUInt64(TimeStamp.Value,0);
            value = Value;
        }
    }
}
于 2013-05-03T17:51:29.920 回答
1

要么您的问题出在其他地方,要么您发布的代码不能准确表示正在运行的内容。或者,也许您的数据顺序非常糟糕,导致 Sort 表现出最坏的情况行为。我觉得最后一个不太可能。

这是我的测试程序,它将 100,000 个DataObject实例添加到 anArrayList然后调用Sort. 它在我的机器上执行不到 50 毫秒。

请注意,这是 .NET 4.5,而不是 3.5。但是,我无法想象这种排序在早期版本中被破坏得如此可怕。

public class DataObject : IComparable
{
    private DateTime timeStamp;
    private string description;
    private string detail;

    public DataObject(DateTime inTimeStamp, string inDescription,
                       string inDetail)
    {
        this.timeStamp = inTimeStamp;
        this.description = inDescription;
        this.detail = inDetail;
    }

    public int CompareTo(object that)
    {
        DataObject myThat = (DataObject)that;
        return this.timeStamp.CompareTo(myThat.timeStamp);
    }
}

public class Program
{
    private static void Main(string[] args)
    {
        // Create an ArrayList with DataObject items.
        const int NumItems = 100000;

        // The items get random time stamps within the last year
        DateTime endDate = DateTime.Now;
        DateTime baseDate = endDate.AddYears(-1);
        int secondsRange = (int)((endDate - baseDate).TotalSeconds);
        Random rnd = new Random();

        Console.WriteLine("Adding {0} items to list.", NumItems);
        ArrayList dataList = new ArrayList();
        for (int i = 0; i < NumItems; ++i)
        {
            DateTime ts = baseDate.AddSeconds(rnd.Next());
            DataObject item = new DataObject(ts, "Foo", "bar");
            dataList.Add(item);
        }
        Console.Write("Sorting list...");
        Stopwatch sw = Stopwatch.StartNew();
        dataList.Sort();
        sw.Stop();
        Console.WriteLine("done!");
        Console.WriteLine("Elapsed time {0} ms", sw.ElapsedMilliseconds);
        Console.ReadLine();
    }
}
于 2013-05-03T16:56:41.630 回答