在日常開發(fā)中數(shù)據(jù)集合經(jīng)常的會用到窒升,使用頻率較高的例如 List 翼悴、Dictionary全度,在數(shù)據(jù)集合中每種數(shù)據(jù)結(jié)構(gòu)都有他們的優(yōu)缺點(diǎn)娶聘,所以今天筆者對常用的數(shù)據(jù)集合歸納整理灵临,一是防止自己忘記、二是希望能夠幫助到對此理解不清晰的開發(fā)者
筆者的Unity 開發(fā)版本為 2017.4.2.f2 (.NET 4.6)
有說的不準(zhǔn)確或者錯(cuò)誤的地方歡迎留言指正
Array
- Array:在內(nèi)存上連續(xù)分配的趴荸,而且元素類型是一樣的
- 優(yōu)點(diǎn):可以索引坐標(biāo)訪問 讀取快 缺點(diǎn):增刪慢儒溉,長度不變
//Array:在內(nèi)存上連續(xù)分配的,而且元素類型是一樣的
//優(yōu)點(diǎn):可以索引坐標(biāo)訪問 讀取快 缺點(diǎn):增刪慢发钝,長度不變
int[] intArray = new int[3];
intArray[0] = 0;
string[] stringArray = new string[] { "菜鳥", "海瀾" };//Array
動(dòng)態(tài)數(shù)組(ArrayList)
- ArrayList 不定長的顿涣,連續(xù)分配的;
- 元素沒有類型限制酝豪,任何元素都是當(dāng)成object處理
- 優(yōu)點(diǎn):讀取快 缺點(diǎn):增刪慢涛碑,如果是值類型,會有裝箱操作
//ArrayList 不定長的孵淘,連續(xù)分配的蒲障;
//元素沒有類型限制,任何元素都是當(dāng)成object處理
//優(yōu)點(diǎn):讀取快 缺點(diǎn):增刪慢瘫证,如果是值類型揉阎,會有裝箱操作
ArrayList arrayList = new ArrayList();
arrayList.Add("菜鳥");
arrayList.Add("海瀾");
arrayList.Add(9257);//add增加長度
List 詳情請看MSDN備注中的性能相關(guān)
- List:也是Array,內(nèi)存上都是連續(xù)擺放;不定長背捌;泛型毙籽,保證類型安全,避免裝箱拆箱
- 優(yōu)點(diǎn):讀取快 缺點(diǎn):增刪慢
//List:也是Array毡庆,內(nèi)存上都是連續(xù)擺放;不定長坑赡;泛型,保證類型安全么抗,避免裝箱拆箱
//優(yōu)點(diǎn):讀取快 缺點(diǎn):增刪慢
List<int> intList = new List<int>() { 1, 2, 3, 4 };
intList.Add(5);
intList.Add(6);
LinkedList
- LinkedList:泛型的特點(diǎn);鏈表毅否,元素不連續(xù)分配,每個(gè)元素都有記錄前后節(jié)點(diǎn)
- 節(jié)點(diǎn)值可以重復(fù)
- 優(yōu)點(diǎn):增刪方便 缺點(diǎn):不能進(jìn)行下標(biāo)索引訪問蝇刀,找元素就只能遍歷 查找不方便
LinkedList<int> linkedList = new LinkedList<int>();
linkedList.AddFirst(123);
linkedList.AddLast(456);
bool isContain = linkedList.Contains(123);
LinkedListNode<int> node123 = linkedList.Find(123); //元素123的位置 從頭查找
linkedList.AddBefore(node123, 123);
linkedList.AddAfter(node123, 789);
Queue
- 在鏈表的特點(diǎn)上添加先進(jìn)先出特點(diǎn)
//Queue 就是鏈表 先進(jìn)先出 放任務(wù)延遲執(zhí)行螟加,A不斷寫入日志任務(wù) B不斷獲取任務(wù)去執(zhí)行
Queue<string> numbers = new Queue<string>();
numbers.Enqueue("one");
numbers.Enqueue("two");
numbers.Enqueue("three");
numbers.Enqueue("four");
numbers.Enqueue("four");
numbers.Enqueue("five");
Stack
Stack對應(yīng)MSDN地址
- 在鏈表的基礎(chǔ)上添加先進(jìn)后出特點(diǎn)
Stack<string> numbers = new Stack<string>();
numbers.Push("one");
numbers.Push("two");
numbers.Push("three");
numbers.Push("four");
numbers.Push("five");//放進(jìn)去
HashSet
參考文章如下
HashTable、HashSet和Dictionary的區(qū)別
國外開發(fā)者HashTable熊泵、HashSet和Dictionary的比較文章
- 這個(gè)HashSet就厲害了仰迁,hash分布,不僅僅能動(dòng)態(tài)擴(kuò)容、自動(dòng)去重顽分,而且還有交、叉施蜜、并卒蘸、補(bǔ)功能
HashSet<string> hashSet = new HashSet<string>();
hashSet.Add("1111");
hashSet.Add("2222");
hashSet.Add("3333");
hashSet.Add("1111");
hashSet.Add("1111");
hashSet.Add("1111");
Debug.Log($"第一次打印開始{new string('*', 20)}");
foreach (var item in hashSet)
{
Debug.Log(item);
}
Debug.Log($"hashSet含有的Count為:{hashSet.Count}");
Debug.Log($"第一次打印結(jié)束{new string('*', 20)}");
打印結(jié)果:
- 對應(yīng)的交、補(bǔ)、并缸沃、補(bǔ)
{
HashSet<string> hashSet = new HashSet<string>();
hashSet.Add("1111");
hashSet.Add("2222");
hashSet.Add("3333");
hashSet.Add("A12435");
hashSet.Add("B12435");
hashSet.Add("C12435");
HashSet<string> hashSet1 = new HashSet<string>();
hashSet1.Add("1111");
hashSet1.Add("1111");
hashSet1.Add("1111");
hashSet1.Add("2222");
hashSet1.Add("3333");
hashSet1.Add("a12435");
hashSet1.Add("b12435");
hashSet1.Add("c12435");
HashSet<string> hashSet2 = new HashSet<string>();
hashSet2.Add("1111");
hashSet2.Add("1111");
hashSet2.Add("1111");
hashSet2.Add("2222");
hashSet2.Add("3333");
hashSet2.Add("a12435");
hashSet2.Add("b12435");
hashSet2.Add("c12435");
HashSet<string> hashSet3 = new HashSet<string>();
hashSet3.Add("1111");
hashSet3.Add("1111");
hashSet3.Add("1111");
hashSet3.Add("2222");
hashSet3.Add("3333");
hashSet3.Add("a12435");
hashSet3.Add("b12435");
hashSet3.Add("c12435");
HashSet<string> hashSet4 = new HashSet<string>();
hashSet4.Add("1111");
hashSet4.Add("1111");
hashSet4.Add("1111");
hashSet4.Add("2222");
hashSet4.Add("3333");
hashSet4.Add("a12435");
hashSet4.Add("b12435");
hashSet4.Add("c12435");
Debug.Log("計(jì)算交集開始");
hashSet1.IntersectWith(hashSet);//交集(hashSet1與hashSet共有的元素集合恰起,并賦值給hashSet1)
foreach (var item in hashSet1)
{
Debug.Log(item);
}
Debug.Log("計(jì)算交集結(jié)束");
Debug.Log("計(jì)算補(bǔ)集開始");
hashSet2.SymmetricExceptWith(hashSet);//補(bǔ)集(除共有意外的所有元素集合,并賦值給hashSet2)
foreach (var item in hashSet2)
{
Debug.Log(item);
}
Debug.Log("計(jì)算補(bǔ)集結(jié)束");
Debug.Log("計(jì)算并集開始");
hashSet3.UnionWith(hashSet);//并集(兩個(gè)集合含有的所有元素趾牧,并賦值給hashSet3)
foreach (var item in hashSet3)
{
Debug.Log(item);
}
Debug.Log("計(jì)算并集結(jié)束");
Debug.Log("計(jì)算差集開始");
hashSet4.ExceptWith(hashSet);//差集(hashSet1有而hashSet沒有的元素集合检盼,并賦值給hashSet4)
foreach (var item in hashSet4)
{
Debug.Log(item);
}
Debug.Log("計(jì)算差集結(jié)束");
}
打印輸出
SortedSet
C#編程中HashSet和SortedSet的講解及區(qū)別
- 也是有去重和交、叉翘单、并吨枉、補(bǔ)、功能哄芜,并且可自動(dòng)排序個(gè)自定義排序
IComparer<T> comparer 自定義對象要排序貌亭,就用這個(gè)指定
SortedSet<string> sortedSet = new SortedSet<string>();
sortedSet.Add("a123456");
sortedSet.Add("b123456");
sortedSet.Add("c123456");
sortedSet.Add("12435");
sortedSet.Add("12435");
sortedSet.Add("12435");
foreach (var item in sortedSet)
{
Debug.Log(item);
}
打印信息
Hashtable
- Hashtable key-value 體積可以動(dòng)態(tài)增加 根據(jù)key計(jì)算一個(gè)地址,然后在對應(yīng)的地址中放入key - value信息
- object-裝箱拆箱問題 如果不同的key計(jì)算得到相同的地址认臊,則第二個(gè)在前面地址上 + 1
- 查找的時(shí)候圃庭,如果地址對應(yīng)數(shù)據(jù)信息的key不對,那就 + 1查找(出現(xiàn)上面一條的情況下)
- 優(yōu)點(diǎn):查找個(gè)數(shù)據(jù) 一次定位失晴; 增刪 一次定位剧腻; 增刪查改 都很快
- 缺點(diǎn):浪費(fèi)了空間,Hashtable是基于數(shù)組實(shí)現(xiàn)涂屁,如果數(shù)據(jù)太多恕酸,造成重復(fù)相同地址(第二條),效率下降
Hashtable table = new Hashtable();
table.Add("123", "456");
table[1] = 456;
table[2] = 789;
table[3] = 101112;
table[1] = "0000";
table["海瀾"] = 9257;
foreach (DictionaryEntry objDE in table)
{
Debug.Log(objDE.Key.ToString());
Debug.Log(objDE.Value.ToString());
}
//線程安全
Hashtable.Synchronized(table);//只有一個(gè)線程寫 多個(gè)線程讀
Dictionary
出場率最高的key -value 數(shù)據(jù)集合胯陋,也是大家很熟悉的
- 字典:泛型蕊温;key - value,增刪查改 都很快遏乔;有序的
- 典不是線程安全 安全字典用ConcurrentDictionary
Dictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(5, "e");
dic.Add(4, "d");
dic.Add(3, "c");
dic.Add(2, "b");
dic.Add(1, "a");
foreach (var item in dic)
{
Debug.Log($"Key:{item.Key}, Value:{item.Value}");
}
SortedDictionary
- 自動(dòng)排序
SortedDictionary<int, string> dic = new SortedDictionary<int, string>();
dic.Add(1, "a");
dic.Add(5, "e");
dic.Add(3, "v");
dic.Add(2, "b");
dic.Add(4, "d");
dic[6] = "f";
foreach (var item in dic)
{
Debug.Log($"Key:{item.Key}, Value:{item.Value}");
}
打印結(jié)果:
SortedList
- 自動(dòng)排序
SortedList sortedList = new SortedList();//IComparer
sortedList.Add("1", "a");
sortedList.Add("2", "b");
sortedList.Add("3", "c");
var keyList = sortedList.GetKeyList();
var valueList = sortedList.GetValueList();
sortedList.TrimToSize();//用于最小化集合的內(nèi)存開銷
- ConcurrentQueue 線程安全版本的Queue
- ConcurrentStack線程安全版本的Stack
- ConcurrentBag線程安全的對象集合
- ConcurrentDictionary線程安全的Dictionary
- BlockingCollection線程安全集合類
詳情查看System.Collections.Concurrent Namespace
最后附上相應(yīng)的[IDictionary選項(xiàng) - 性能測試 - SortedList與SortedDictionary vs. Dictionary與Hashtable义矛,不方便看的小伙伴可以用谷歌瀏覽器一鍵翻譯,翻譯比較準(zhǔn)確
IEnumerable補(bǔ)充
IEnumerable經(jīng)常會見到盟萨,都是知道他是迭代器凉翻,但是具體怎么個(gè)迭代,又有點(diǎn)可能說不清捻激,下面筆者舉個(gè)小例子
public class YieldDemo
{
public IEnumerable<int> CustomEnumerable()
{
for (int i = 0; i < 10; i++)
{
yield return this.Get(i);
}
}
public IEnumerable<int> Common()
{
List<int> intList = new List<int>();
for (int i = 0; i < 10; i++)
{
intList.Add(this.Get(i));
}
return intList;
}
private int Get(int num)
{
Thread.Sleep(200);
return num * DateTime.Now.Second;
}
}
Task.Run(()=>
{
YieldDemo yieldDemo = new YieldDemo();
foreach (var item in yieldDemo.CustomEnumerable())
{
Debug.Log(item);//按需獲取制轰,要一個(gè)拿一個(gè)
}
Debug.Log("*******************************************");
foreach (var item in yieldDemo.Common())
{
Debug.Log(item);//先全部獲取,然后一起返還
}
});
效果如下: