第1章 - 集合
嗨,朋友!我是长安。
在基础教程中,我们学习了数组,但数组有个缺点:大小固定,不能动态增减。这一章我们要学习"集合",它们比数组更灵活、更强大!
🤔 什么是集合?
集合就像一个可以自动伸缩的容器,可以随时添加、删除元素。
类比:
- 数组:像一排固定的储物柜,有10个柜子就是10个,不能增减
- 集合:像一个可伸缩的背包,想装多少就装多少
🌟 常用集合类型
C# 提供了多种集合类型,每种都有特定的用途:
| 集合类型 | 特点 | 适用场景 |
|---|---|---|
| List<T> | 动态数组 | 最常用,类似数组但可变长 |
| Dictionary<TKey, TValue> | 键值对 | 需要通过键快速查找值 |
| HashSet<T> | 不重复集合 | 需要存储唯一值 |
| Queue<T> | 队列 | 先进先出(FIFO) |
| Stack<T> | 栈 | 后进先出(LIFO) |
📚 List<T> - 动态数组
List<T> 是最常用的集合,T 表示泛型(下一章会详细讲)。
创建 List
using System;
using System.Collections.Generic; // 必须引入这个命名空间
namespace CollectionsDemo
{
class Program
{
static void Main(string[] args)
{
// 创建一个存储整数的 List
List<int> numbers = new List<int>();
// 创建时初始化
List<string> names = new List<string> { "张三", "李四", "王五" };
// 输出
Console.WriteLine($"names 有 {names.Count} 个元素");
}
}
}
添加元素
List<string> fruits = new List<string>();
// 添加单个元素
fruits.Add("苹果");
fruits.Add("香蕉");
fruits.Add("橙子");
// 添加多个元素
fruits.AddRange(new[] { "葡萄", "西瓜" });
// 在指定位置插入
fruits.Insert(1, "草莓"); // 在索引1的位置插入
Console.WriteLine($"水果数量:{fruits.Count}");
访问元素
List<string> fruits = new List<string> { "苹果", "香蕉", "橙子" };
// 通过索引访问
Console.WriteLine(fruits[0]); // 输出:苹果
Console.WriteLine(fruits[1]); // 输出:香蕉
// 使用 foreach 遍历
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
// 使用 for 循环遍历
for (int i = 0; i < fruits.Count; i++)
{
Console.WriteLine($"{i}: {fruits[i]}");
}
删除元素
List<string> fruits = new List<string> { "苹果", "香蕉", "橙子", "香蕉" };
// 删除指定元素(只删除第一个匹配的)
fruits.Remove("香蕉");
// 删除指定索引的元素
fruits.RemoveAt(0);
// 删除所有匹配的元素
fruits.RemoveAll(f => f == "香蕉");
// 清空所有元素
fruits.Clear();
查找元素
List<string> fruits = new List<string> { "苹果", "香蕉", "橙子" };
// 检查是否包含某个元素
bool hasApple = fruits.Contains("苹果"); // true
// 查找元素的索引
int index = fruits.IndexOf("香蕉"); // 1
// 查找满足条件的第一个元素
string fruit = fruits.Find(f => f.StartsWith("橙")); // "橙子"
// 查找满足条件的所有元素
List<string> result = fruits.FindAll(f => f.Length > 2);
完整示例:学生成绩管理
using System;
using System.Collections.Generic;
using System.Linq;
namespace ListDemo
{
class Program
{
static void Main(string[] args)
{
// 创建成绩列表
List<int> scores = new List<int>();
// 输入5个学生的成绩
Console.WriteLine("请输入5个学生的成绩:");
for (int i = 0; i < 5; i++)
{
Console.Write($"学生{i + 1}的成绩:");
int score = int.Parse(Console.ReadLine());
scores.Add(score);
}
// 计算平均分
double average = scores.Average();
Console.WriteLine($"\n平均分:{average:F2}");
// 找出最高分和最低分
int maxScore = scores.Max();
int minScore = scores.Min();
Console.WriteLine($"最高分:{maxScore}");
Console.WriteLine($"最低分:{minScore}");
// 统计及格人数(≥60分)
int passCount = scores.Count(s => s >= 60);
Console.WriteLine($"及格人数:{passCount}");
// 按分数排序(从高到低)
scores.Sort((a, b) => b.CompareTo(a));
Console.WriteLine("\n成绩排名(从高到低):");
for (int i = 0; i < scores.Count; i++)
{
Console.WriteLine($"第{i + 1}名:{scores[i]}分");
}
Console.ReadKey();
}
}
}
📖 Dictionary<TKey, TValue> - 字典
字典存储键值对,可以通过键快速查找值。
创建 Dictionary
// 创建一个存储学生姓名和成绩的字典
Dictionary<string, int> studentScores = new Dictionary<string, int>();
// 创建时初始化
Dictionary<string, string> phoneBook = new Dictionary<string, string>
{
{ "张三", "138-1234-5678" },
{ "李四", "139-8765-4321" },
{ "王五", "150-1111-2222" }
};
添加和修改元素
Dictionary<string, int> scores = new Dictionary<string, int>();
// 添加元素
scores.Add("张三", 85);
scores.Add("李四", 92);
// 使用索引添加/修改
scores["王五"] = 78; // 如果不存在就添加,存在就修改
scores["张三"] = 88; // 修改张三的成绩
// 尝试添加(如果键已存在则返回 false)
bool added = scores.TryAdd("李四", 95); // false,因为李四已存在
访问元素
Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "张三", 85 },
{ "李四", 92 },
{ "王五", 78 }
};
// 通过键访问值
int score = scores["张三"]; // 85
// 安全访问(如果键不存在不会报错)
if (scores.TryGetValue("张三", out int zhangScore))
{
Console.WriteLine($"张三的成绩:{zhangScore}");
}
// 遍历字典
foreach (KeyValuePair<string, int> item in scores)
{
Console.WriteLine($"{item.Key}: {item.Value}分");
}
// 或者这样遍历
foreach (var item in scores)
{
Console.WriteLine($"{item.Key}: {item.Value}分");
}
删除和查找
Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "张三", 85 },
{ "李四", 92 }
};
// 删除元素
scores.Remove("张三");
// 检查是否包含某个键
bool hasKey = scores.ContainsKey("李四"); // true
// 检查是否包含某个值
bool hasValue = scores.ContainsValue(92); // true
// 获取所有的键
var keys = scores.Keys;
// 获取所有的值
var values = scores.Values;
// 清空
scores.Clear();
完整示例:电话簿
using System;
using System.Collections.Generic;
namespace DictionaryDemo
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, string> phoneBook = new Dictionary<string, string>
{
{ "张三", "138-1234-5678" },
{ "李四", "139-8765-4321" }
};
while (true)
{
Console.WriteLine("\n===== 电话簿 =====");
Console.WriteLine("1. 添加联系人");
Console.WriteLine("2. 查询电话");
Console.WriteLine("3. 删除联系人");
Console.WriteLine("4. 显示所有联系人");
Console.WriteLine("0. 退出");
Console.Write("请选择操作:");
string choice = Console.ReadLine();
switch (choice)
{
case "1":
Console.Write("姓名:");
string name = Console.ReadLine();
Console.Write("电话:");
string phone = Console.ReadLine();
if (phoneBook.ContainsKey(name))
{
Console.WriteLine("该联系人已存在!");
}
else
{
phoneBook.Add(name, phone);
Console.WriteLine("添加成功!");
}
break;
case "2":
Console.Write("请输入姓名:");
string searchName = Console.ReadLine();
if (phoneBook.TryGetValue(searchName, out string foundPhone))
{
Console.WriteLine($"{searchName}的电话是:{foundPhone}");
}
else
{
Console.WriteLine("未找到该联系人!");
}
break;
case "3":
Console.Write("请输入要删除的姓名:");
string deleteName = Console.ReadLine();
if (phoneBook.Remove(deleteName))
{
Console.WriteLine("删除成功!");
}
else
{
Console.WriteLine("未找到该联系人!");
}
break;
case "4":
Console.WriteLine("\n所有联系人:");
foreach (var contact in phoneBook)
{
Console.WriteLine($"{contact.Key}: {contact.Value}");
}
break;
case "0":
Console.WriteLine("再见!");
return;
default:
Console.WriteLine("无效的选择!");
break;
}
}
}
}
}
🎯 HashSet<T> - 不重复集合
HashSet<T> 自动去除重复元素,适合需要存储唯一值的场景。
using System;
using System.Collections.Generic;
namespace HashSetDemo
{
class Program
{
static void Main(string[] args)
{
// 创建 HashSet
HashSet<int> numbers = new HashSet<int>();
// 添加元素(重复的会自动忽略)
numbers.Add(1);
numbers.Add(2);
numbers.Add(2); // 这个2不会被添加
numbers.Add(3);
Console.WriteLine($"元素个数:{numbers.Count}"); // 输出:3
// 遍历
foreach (int num in numbers)
{
Console.WriteLine(num); // 输出:1 2 3
}
// 集合运算
HashSet<int> set1 = new HashSet<int> { 1, 2, 3, 4 };
HashSet<int> set2 = new HashSet<int> { 3, 4, 5, 6 };
// 并集
set1.UnionWith(set2);
Console.WriteLine("并集:" + string.Join(", ", set1)); // 1, 2, 3, 4, 5, 6
// 交集
HashSet<int> set3 = new HashSet<int> { 1, 2, 3, 4 };
set3.IntersectWith(set2);
Console.WriteLine("交集:" + string.Join(", ", set3)); // 3, 4
Console.ReadKey();
}
}
}
📝 本章小结
这一章我们学习了:
- ✅ 集合的概念和优势
- ✅
List<T>动态数组的使用 - ✅
Dictionary<TKey, TValue>字典的使用 - ✅
HashSet<T>不重复集合的使用 - ✅ 如何选择合适的集合类型
💡 集合选择建议
- List<T>:默认选择,90% 的情况都用它
- Dictionary<TKey, TValue>:需要通过键查找值时使用
- HashSet<T>:需要存储唯一值时使用
- Queue<T>:需要先进先出时使用
- Stack<T>:需要后进先出时使用
🎯 下一步
掌握了集合的使用后,下一章我们要学习"泛型"——让你的代码更通用、更安全!
💪 练习题
- 创建一个 List,存储5个城市名称,然后按字母顺序排序并输出
- 创建一个 Dictionary,存储5个国家和对应的首都,实现查询功能
- 用 HashSet 存储一组数字,自动去除重复项
- 实现一个简单的购物车功能:可以添加商品、删除商品、显示所有商品
答案提示
- 使用
List<string>,然后调用Sort()方法 - 使用
Dictionary<string, string>,用TryGetValue()查询 - 直接添加到
HashSet<int>中,重复的会自动去除 - 使用
Dictionary<string, int>存储商品名和数量
