ArrayList怎么快速去掉重复项?

xiaoqhuang 2006-10-24 02:50:54
不要2层循环,有什么快速的方法吗?或有没现在函数?
...全文
34320 53 打赏 收藏 举报
写回复
53 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
BurningM 2006-12-19
  • 打赏
  • 举报
回复
我也特意测试了下,先插入排序后删除,确实比一条一条判断是否存在后再插入快的多(近2个数量级的差别!数量越大差别越大)
但是,最快的仍然是用Hashtable(其实这还是先判断是否存在后插入),比插入后排序高又近一个数量级(5倍以上速度)
bill024 2006-12-18
  • 打赏
  • 举报
回复
mark
喝醉的咖啡 2006-10-27
  • 打赏
  • 举报
回复
或者,是先放到 DictionaryEntry 里,再放到 hash 表里的
那么检索的时候,显然不是对 Key 进行检索——因为 Key 是 DictionaryEntry 的一部分,而应该是 Contains() ContainsKey(), ContainsValue() 分别对 Key 和 Value 的 HashCode 进行检索。——这本是 hash 类数据结构快的原因,如此来说,假如本例要压入的并非 string,那就要特别注意根据需要重写 Equals() 和 GetHashCode() 方法了

> 我用Hashcode的时候,用的是 ht.Add(v, null)
也就是说本例中用 string 做 key,value 无所谓了
那么,假如 .NET 有更简单的 hash 类数据结构,那么是不是就更节约一些了(直接压入对象,而不必用 DictionaryEntry 包装)?

比如自己实现 hash 表,呵呵


----------------------------------
为容器类指定一个合理的初始容积不是更好
-----------------------------------
我的意思一样,只是不特指某种数据结构,预先设置最大的填充因子,减少动态增加次数。

非常感谢,因为工作性质原因,虽然明白底层的原理,但因为很少与具体的语言、平台很深入的打交道,所以对具体的例如 .NET 中是什么样的现状不是很了解。
经此一贴,知道了 .NET 的 HashTable 是 Java 里的 HashMap,而不是 Java 的 HashTable

Thanks for all.
喝醉的咖啡 2006-10-27
  • 打赏
  • 举报
回复
非常感谢,因为太长没仔细看你的测试——来个结论看结论就好了,哈哈

>到于Contains() 方法,对ArrayList而言,就是遍历实现的,已经有人明确说过了,
而HashTable的Contains() 和 ContainsKey()则是同一实现,时间复杂度为O(1),

请教,ContainsKey() 又是如何实现的?

>而在 C# 中,基于优化的原因(具体细节不记得了)
只记得是编译时做的优化,细节不记得了,那肯定是 .NET 而不是 C# 的功劳。
但代码中的 "333" 也好,数字 5 也好,都是会被自动创建为对象,编译器优化指的是并没有为它们重复分配内存,所以例中的几个引用指向统一地址。提到这一问题是因为说到对象的比较——值是否重复还是引用是否重复的问题。
不过我理解的的确不够明确:GetHashCode() 应该指的是对对象的值的 hash(最好根据需要重写),从而便于用于 hash 类数据结构。
那么
-----------------------------------
补充:
而在 C# 中,基于优化的原因(具体细节不记得了),如果你这么声明几个变量:
string a = "1";
string b = "1";
string c = b;
MessageBox.Show(a.GetHashCode() + " " + b.GetHashCode() + " " + c.GetHashCode());
会发现它们的 HashCode 相同,要小心。
-----------------------------------
其实是两个问题:
1、相同引用——比较两个对象时要小心,是比较值还是比较引用?
2、GetHashCode() 方法——是对值的 hash,实际上可以用来比较两个不同对象的值是否相同
那么,延伸得到相同的结论:

做对象比较的时候,如果是自定义对象,别忘了根据需要重写比较方法或者 ==
而对于自定义对象,别忘了根据需要重写 GetHashCode() 方法

这才是我想要表达的意思,这样表达可能会更准确一些。

另外,发了以后才想起数据结构的知识,HashTable 检索的速度也会快一些(好多年了,都记不准确了)才有上面的问题请教:
HashTable 类检索时比较的是 key 的 hashcode 还是 key ?

比如取出一个对象的时候,是按指定的 key 去 Keys 中检索?
因为按照我的理解,HashTable 是分别对 Keys 和 Values 两个 hash 数据结构进行操作,在 Keys 中 用传入的 key 的 hashcode 检索出 key 的值——也就是 object 的存储位置,然后取出来
——也就是说,这里首先是一个 Key-Value Pair 的关系。而 Key 和 Value 分别存放在 Keys 和 Values 两个 hash 表中(甚至前者都可能不是 hash 表),是不是这样?
amnoh 2006-10-27
  • 打赏
  • 举报
回复
to piggybank(吞硬币的小猪):
--------------------------------
虽然没测试过,但我想你的应用如果使用 hash 类数据结构,效率不会有太大的提高:毕竟 hash 仅仅是将对对象本身的比较改成了对 Key 的比较,那么 key 又是什么呢?另外,hash 数据结构的特点是存入快。
--------------------------------
我想你虽然感谢了,但可能没看我给出的代码和运行结果,或者没看到那一步吧,
我用Hashcode的时候,用的是 ht.Add(v, null),
就是将对象做为键,而值列用的是null,这正是为了排除重复项,
到于Contains() 方法,对ArrayList而言,就是遍历实现的,已经有人明确说过了,
而HashTable的Contains() 和 ContainsKey()则是同一实现,时间复杂度为O(1),
它的ContainsValue()方法则和ArrayList的Contains()一样,遍历实现.
数据的重复度越是高,HashTable的实现就高效.

----------------------------------
那么,有一个改进的可能性就是减少动态分配内存的次数:比如事前知道确定的数据数量,然后一次性申请一块足够大的内存,避免动态增加:此时在你的例子中 ArrayList 还不如 string[n] 好用呢,呵呵
----------------------------------
用一个没有溢出处理的ArrayList???
为容器类指定一个合理的初始容积不是更好

-----------------------------------
补充:
而在 C# 中,基于优化的原因(具体细节不记得了),如果你这么声明几个变量:
string a = "1";
string b = "1";
string c = b;
MessageBox.Show(a.GetHashCode() + " " + b.GetHashCode() + " " + c.GetHashCode());
会发现它们的 HashCode 相同,要小心。
-----------------------------------
这不是优化的原因,这是本应该的事情,如果它们的HashCode不一样的话,
难道说有一HashTable ht,我弄个ht[a] = "333",
那我以后除了ht[a]岂不是没别的办法取值了,因为 a, b ,c 的HashCode不同呀...
这个HashCode不仅在C#,在VB中也是相同的...

算了,楼主你快结帖吧,反正你的问题也差不多了,
我的战神这两天V了,打算星期天解V,
你要是感觉SS不好用,就出皇骑得了,我给你免费供应汗血 :)
www_123du_com 2006-10-27
  • 打赏
  • 举报
回复
/*amnoh say:
amnoh :
string s1 = "h" + "i";
string s2 = "hi";

s1和s2的引用不同,但hashcode是相同的
*/
这里的s1与s2的引用是相同的,呵呵。
这是两个原因:
1.编译器。编译器在编译时会把直接量"h"+"i"组合成"hi"。
2.拘留池。参见MSDN(http://www.123du.com/#b=0&p=1&t=%u62D8%u7559%u6C60%20site%3Amicrosoft.com&s=1&o=0)
如果说:
string s1 = "hi";
string s2 = s1.Substring(0, 1)+"i";
那么s1与s2就是引用不同。
但其实针对Hashcode,引用不重要,重要的是值(Equls方法)。
他们值相同,那么Hashcode就必须相同。
amnoh 2006-10-26
  • 打赏
  • 举报
回复
楼主的测试,应该说问题不少
1. 不应该在循环中创建Random对象, 因为这个操作比较耗时,乘以N后,被放大了,
如果方法1 和 方法2 真正消耗的时间是 t1, t2,那现在看到的时间其实是 (tCreating * N + t1) 和 (tCreating * N + t2),它们之间的比例关系被影响,除非 t1 原本就等 t2,但这种假设是不存在的.
2. 因为是在添加过程中生成的随机数,所以 两组方法所用的测试数据不同,不严谨.应该提前 生成测试数据,然后再用这组数据进行测试.

//以下预先生成测试数据
const int testSize = 12000; //为了方便更改规模
int[] testArray = new int[testSize];
Random rd = new Random();
for(int iLoop = 0; iLoop < testArray.Length; iLoop++) {
testArray[iLoop] = rd.Next(1, 10000);
}

//以下代码中,去掉了楼主原先生成随机数的代码.
//第二个方法中,因为变量不好认,改动了一下
//我是在控制台程序中测试,所以将Response.Write改成了Console.WriteLine
//判断再插入
ArrayList al = new ArrayList();
DateTime d1 = System.DateTime.Now;//开始
for(int i=0;i<testSize;i++) {
if(!al.Contains(testArray[i])) {
al.Add(testArray[i]);
}
}
DateTime d2 = System.DateTime.Now;//结束
TimeSpan ts = d2-d1;
Console.WriteLine("判断后再插入, 最后插入数目:{0}, 耗时 {1}毫秒.",al.Count,ts.TotalMilliseconds);

//插入再判断, 因为楼主起的名原为al*,这后边的是数字1,还是字母l分不清,所以改了个变量名
ArrayList secondAL = new ArrayList();
DateTime d3 = System.DateTime.Now;//开始
for(int i=0;i<testSize;i++) {
secondAL.Add(testArray[i]);
}
secondAL.Sort();//排序
for(int i=0;i<secondAL.Count-1;i++) {
if(secondAL[i].Equals(secondAL[i+1])) {
secondAL.RemoveAt(i);//去重复项
--i;
}
}
DateTime d4 = System.DateTime.Now;//结束
TimeSpan ts2 = d4-d3;
Console.WriteLine("插入后再判断, 最后插入数目:{0}, 耗时 {1}毫秒.", secondAL.Count, ts2.TotalMilliseconds);
--------------------------------------------------


运行结果分析分开贴,免得帖子太长
喝醉的咖啡 2006-10-26
  • 打赏
  • 举报
回复
本例中,究竟减少 装箱/拆箱,并减少动态分配内存的情况下,与采用 HashTable 获得更好的检索速度相比,哪一种更好还不清楚,期待有精力的朋友提供测试数据,不胜感激,呵呵
喝醉的咖啡 2006-10-26
  • 打赏
  • 举报
回复
〉如果很大,把它放进DataTable用SQL代码去除重复,重复得留一个。

其实是利用 DataTable 的算法实现——人家已经优化过了
是个狡猾的方法,只是不知道是否有效——毕竟优化目的未必相同
喝醉的咖啡 2006-10-26
  • 打赏
  • 举报
回复
太好了,很多人喜欢测试并提供具体数据,感谢感谢

===========================

1、首先是关于比较的问题的几个细节
判断两个对象是否相等与是否相同不是一个概念:注意了,如下例子
比较两个字符串变量 (a == b),结果为 True,是因为 string 重载了 == 操作符,而其它类,比如你自己写的类未必,它们会比较 HashCode(代替比较指针地址)。

HashTable/HashMap 其实也有比较的:只不过不是对对象进行比较,而是对你放进去的时候用的 key 进行比较

那么,当你把一个 object 放到 hash 类数据结构中时,显然要提供一个 key,如果你提供的是 object 的 hashCode,那与使用数组区别不大

所以有朋友说到 Contains() 方法,其实一定也是遍历的——实在不行 dasm 源代码看看

虽然没测试过,但我想你的应用如果使用 hash 类数据结构,效率不会有太大的提高:毕竟 hash 仅仅是将对对象本身的比较改成了对 Key 的比较,那么 key 又是什么呢?另外,hash 数据结构的特点是存入快。

那么,有一个改进的可能性就是减少动态分配内存的次数:比如事前知道确定的数据数量,然后一次性申请一块足够大的内存,避免动态增加:此时在你的例子中 ArrayList 还不如 string[n] 好用呢,呵呵


补充:
而在 C# 中,基于优化的原因(具体细节不记得了),如果你这么声明几个变量:
string a = "1";
string b = "1";
string c = b;
MessageBox.Show(a.GetHashCode() + " " + b.GetHashCode() + " " + c.GetHashCode());
会发现它们的 HashCode 相同,要小心。


2、优化的问题
好比著名的油漆桶故事(今天在三个帖子里都遇到这样的案例),当你的数组里的数据越来越多时,比较操作所需要遍历的数据量越来越大——刷油漆的时候,越刷距离油漆桶越来越远,来回开销越来越大——这是无法避免的。
只能考虑能否从更上游进行优化:例如,假如你的数据是从数据库获得的,能否当时就用一个 DISTNCT 排除一下,等等?

3、BOX/UNBOX
ArrayList 中存放的是 Object,既然仅仅针对字符串操作,建议使用 System.Collections.Specialized.StringCollection 会稍好一些
我没测试过,但从理论上说会少很多 装箱/拆箱操作,应该会快很多
或者仅仅使用泛型,也会好很多:
〉http://www.microsoft.com/china/MSDN/library/netFramework/netframework/NET.mspx?mfr=true 《CLR 中的泛型简介》
〉最近针对一个由一百万个整数组成的数组进行了快速排序法基准测试,结果表明泛型方法比非泛型方法快三倍。这是由于完全避免了对这些值进行装箱。如果针对由字符串引用组成的数组进行同样的排序,则由于无需在运行时执行类型检查,因此使用泛型方法后性能提高了 20%。


最后,总结一下:
1、在你的例子中,也许用 string[]并事先确定长度,能避免动态分配内存的资源开销
2、用 string[] 或者 StringCollection、泛型 等类型化的数据结构,会减少大量的拆箱/装箱操作
3、本例中,看不出来有必要使用 hash 类数据结构,因为比较操作会有同样的性能开销。而 hash 类数据结构的优势是存入快,可以采用 1 的方式来获得同样效果
4、尽可能在更上游进行优化




xiaoqhuang 2006-10-26
  • 打赏
  • 举报
回复
晕,原来你也是混战神的呀,今天我最郁闷了!!!
299个神射居然打不过人家1级弓和2级弓的混合部队,
属性全30+的狗雄硬是不暴发一次,反而敌人2X属性的英雄暴发了二次伤害!
amnoh 2006-10-26
  • 打赏
  • 举报
回复
我说怎么楼主的ID看着眼熟,原来也是玩战神的....
amnoh 2006-10-26
  • 打赏
  • 举报
回复
上边说漏了话,ArrayList和HashTable保存的都不是对象本身,而是引用,
所以它们只要容积一定,保存不保存对象,占用的内存都是一个定值,而保存的对象是在堆中另外占用空间的,所以才有上边的结论
amnoh 2006-10-26
  • 打赏
  • 举报
回复
HashTable消耗的内存跟数据量和加载因子有很大关系,应该是种以空间换取时间的方法,不过不知道和ArrayList相比,内存占用谁更大,不知怎么测试,对我来说也没必要测试了.
---------------------------
楼主对于容器类,可能有点误会,要实现动态增删,且可以进行随机存取,就得提前在内存中开辟一块空间,然后操作,以后如果不够用了,就另开一块更大的,然后把当前保存的所有对象拷贝过去,再丢掉当前的内存块.
这一点,ArrayList和HashTable没什么太大的区别, 都是用空间换来了方便性,
只不过ArrayList在默认情况下,初始容积为16,不够用时,容积加倍,就是说,它的比例因子为 1.0,这和HashTable的默认比例因子是一样的,只不过ArrayList是增倍,而HashTable是变为大于当前容积两倍的最小质数,另外就是HashTable需要保管键列和值列,是比较多.但真正重要的是,放在外边的对象,它们才是影响内存占用的关键.

所以,数据的重复度越高,数据类型越复杂(其实只要比int复杂一点就够了,string就成),先插入再判断删除的方法,浪费的内存就越多,运行一下上边给出的代码时,你盯着进程管理器看就成了

CSDN_0 2006-10-26
  • 打赏
  • 举报
回复

====
上万的数据放入ArrayList首先就会影响执行速度。

建议大量数据不要用ArrayList
====
xiaoqhuang 2006-10-26
  • 打赏
  • 举报
回复
楼主的钻研精神不错,先赞一个!

其实方法的孰优孰劣,主要还是要针对特定的运用来的.

我针对的是我的应用,所有测试数据也跟应用数据类似(string 型换成int型,其它大小、重复数据都差不多).

针对这个才得出插入后再去除的方法更优,当然,现在测试是HashTable相对最优.
HashTable消耗的内存跟数据量和加载因子有很大关系,应该是种以空间换取时间的方法,不过不知道和ArrayList相比,内存占用谁更大,不知怎么测试,对我来说也没必要测试了.

==============================
你说的
2. 因为是在添加过程中生成的随机数,所以 两组方法所用的测试数据不同,不严谨.应该提前 生成测试数据,然后再用这组数据进行测试.

其实测试数据是一样的,因为我加了个随机数的Seed i,Random rd = new Random(i);, :)
amnoh 2006-10-26
  • 打赏
  • 举报
回复
如果数据的重复度小,例如,当testSize为 12W时, 将random的范围也由1~10,000改到 1~10,0000,那楼主所给的排除算法,表现肯定会好得多,
而这时,用HashTable实现的,比上边的时间则要增加很多,因为testSize的增加给它带来的压力不大,反倒是当random的范围增加时,它的耗时增加更快,这也是楼上 lovefootball(蟑螂(生活就是扯淡--做人要放低姿态)) 所说的写入开销问题.
但可以肯定的是,在取合适容积的情况下,它依然要远远比楼主所给的用ArrayList的算法来得快.
之所以说是楼主所给,是预防有人发现新的实现算法的情况,我的说法是针对目前讨论中出现过的算法而言
amnoh 2006-10-26
  • 打赏
  • 举报
回复
注:因为第一次运行时,程序比较慢,所以去掉了第一次的运行结果. 直接在VS中按Ctrl+F5运行

按以上程序运行,3次结果如下:
判断后再插入, 最后插入数目:7027, 耗时 1312.5毫秒.
插入后再判断, 最后插入数目:7027, 耗时 46.875毫秒.
-------------------------------------------
判断后再插入, 最后插入数目:7008, 耗时 1296.875毫秒.
插入后再判断, 最后插入数目:7008, 耗时 46.875毫秒.
-------------------------------------------
判断后再插入, 最后插入数目:7008, 耗时 1296.875毫秒.
插入后再判断, 最后插入数目:7008, 耗时 46.875毫秒.

从结果可以看出,确实,楼主的说法似乎正确, 判断后再插入 所花费时间是 第二种方法的20多倍,
这个倍数虽然不像楼主给出的数据,但大方向是一致的.
分析一下原因,不难看出,第一种方法中判断是否已存在时,用了ArrayList的Contains方法,MSDN上写的很清楚,这个算法的时间复杂度为O(n),所以, 到了后期,随着al中的元素增多, 每次遍历所需时间也大大增加,整个算法的时间复杂度为O(n^2),
而第二种方法则没有这个问题,先是插入,时间度为O(n),其后判断是否重复的算法,时间复杂度也是O(n),在最糟的情况下,就是所有数据都重复,它也只需进行n-1次删除操作.

现在缩减一下问题规模,将testSize去掉一个0, 成为 1200,
运行结果,5次:
----------------------
判断后再插入, 最后插入数目:1131, 耗时 46.875毫秒.
插入后再判断, 最后插入数目:1131, 耗时 0毫秒.
------------------------------------------
判断后再插入, 最后插入数目:1141, 耗时 46.875毫秒.
插入后再判断, 最后插入数目:1141, 耗时 0毫秒.
-----------------------------------------
判断后再插入, 最后插入数目:1131, 耗时 46.875毫秒.
插入后再判断, 最后插入数目:1131, 耗时 0毫秒.

在1200的规模下,第二种算法的优越性比 12000的规模时要更明显.
可以这样说,当初大家想到的去除重复项的算法都是O(n^2)的,现在楼主找到了一个O(n)的,
而先检查再排除的算法中,并没有好的办法去优化,如果一直保持一个有序的ArrayList,那判断时虽然可以用二分法来大大提高效率,但每插入一次造成的元素移动,其消耗乘以N后,对结果的影响实在起不到多少优化的作用,更糟也是有可能的.

所以,楼主第二种方法之所以胜出,是因为找到了一个比较好的排除算法. 不过真的就胜出了吗?
请将问题规模增加,将原来的1万2千,变成12万,即:
testSize = 120000;

运行3次的结果是:
判断后再插入, 最后插入数目:9999, 耗时 28359.375毫秒.
插入后再判断, 最后插入数目:9999, 耗时 73015.625毫秒.
---------------------------------------------
判断后再插入, 最后插入数目:9999, 耗时 27359.375毫秒.
插入后再判断, 最后插入数目:9999, 耗时 62312.5毫秒.
---------------------------------------------
判断后再插入, 最后插入数目:9999, 耗时 27359.375毫秒.
插入后再判断, 最后插入数目:9999, 耗时 62312.5毫秒.

事实上,当问题规模扩大后,楼主所说的"二种方法在数据量越大的情况下相差越大"的本意并未出现, 其实从1200到12000的结果就能看出,虽然规模增大的情况下,两种算法的所用时间虽然从差值上是变大了,其实 从比例关系上看是缩小了,这一点,在规模扩大到12万时得到了证明,第二种算法的耗时增加的更快,以致都越过了第一种算法,所用时间竟然成了第一种算法所用时间的 2倍多,关系已经倒过来了.

当问题规模很小时, 插入一个对象所用时间即使乘以这个规模N, 也不起眼,但随着规模越来越大,这个开销越来越不能忽视,更重要的一点,在产生随机数时,楼主原本的测试中,范围是1~10000,比规模稍小,但在规模到了12W时,它的范围没变,导致了大量的重复数据,而这11W多的重复数据删除,也是开销剧增的主因之一.

楼主第二种算法中,如果重复数据极多,那么它的效率就会极为糟糕,最极端的情况下,如果所有对象相等,则需要执行N次插入,再执行N次删除; 而检查后再插入的算法则只插入一次,以后虽然遍历次数在增加,但毕竟不用去折腾,所以要好的多. 规模到12W的测试之所以会时间关系倒过来,正是因为重复数据极多.

更需要注意的是,这还只是 int型变量的测度,如果一是个复杂类型,那这种不管好坏先添加再说的算法,会将本应丢弃的对象保存起来,一直到删除时才"释放",这同样问题多多.

第一种算法的问题在哪? 就在于检查的方法上,这个遍历极其糟糕, 如果能找到一个好的检查算法,那情况将彻底改观,所以我一再推荐楼主使用HashTable. 下面再给出用HashTable测试的code.

//HashTable
Hashtable ht = new Hashtable();
DateTime htStartTime = DateTime.Now;
for(int i=0; i<testSize; i++){
if(!ht.ContainsKey(testArray[i])) {
ht.Add(testArray[i],null);
}
}
DateTime htEndTime = DateTime.Now;
TimeSpan htTS = htEndTime - htStartTime;
Console.WriteLine("使用HashTable, 最后插入数目:{0}, 耗时 {1}毫秒.", ht.Count, htTS.TotalMilliseconds);

在规模为1.2W的情况下,运行结果:
使用HashTable, 最后插入数目:6968, 耗时 0毫秒.
使用HashTable, 最后插入数目:6947, 耗时 15.625毫秒.
使用HashTable, 最后插入数目:6975, 耗时 46.875毫秒.
使用HashTable, 最后插入数目:7001, 耗时 0毫秒.
使用HashTable, 最后插入数目:6954, 耗时 46.875毫秒.
使用HashTable, 最后插入数目:6917, 耗时 15.625毫秒.

可以看到,时间极少,最多时也和楼主的第二种算法持平,这种量级中,取时的误差导致结果误差很大. 差不多 1: 1
现在将规模扩大为12W,运行结果:
使用HashTable, 最后插入数目:9999, 耗时 140.625毫秒.
使用HashTable, 最后插入数目:9999, 耗时 140.625毫秒.
使用HashTable, 最后插入数目:9999, 耗时 78.125毫秒.
使用HashTable, 最后插入数目:9999, 耗时 62.5毫秒.
使用HashTable, 最后插入数目:9999, 耗时 78.125毫秒.
使用HashTable, 最后插入数目:9999, 耗时 93.75毫秒.

将规模扩大到12W时,用HashTable的实现,耗时并没有和ArrayList实现的那样,多到吓人,不同结果的误差,还是取时误差还大. 就是按140算,比到上边那个28359的结果,现在耗时已经成了 1: 200.

规模继续扩大到120W,
使用HashTable, 最后插入数目:9999, 耗时 437.5毫秒.
使用HashTable, 最后插入数目:9999, 耗时 375毫秒.
...

这时已经没有办法比较了,因为我不敢用ArrayList去试 :).
hsghxm 2006-10-25
  • 打赏
  • 举报
回复
用hashtable试试吧。
givenchy 2006-10-25
  • 打赏
  • 举报
回复
用hashtable试试吧。
加载更多回复(33)
发帖
C#

10.8w+

社区成员

.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
帖子事件
创建了帖子
2006-10-24 02:50
社区公告

让您成为最强悍的C#开发者