C# 集合
简介
集合表示一组具有某种性质的数学元素,引用到程序设计中表示一组具有相同性质的对象。集合的大小可以动态调整,也可以在运行时添加或删除元素
官方文档
集合基类接口
- ICollection
- IEnumerable
- IQueryable
集合列表
- List
- ArrayList
- Dictionary
- List<KeyValuePair<TKey, TValue>>
- Hashtable
- Hashset
- Queue
- Stack
- SortedList
- SortedDictionary
- LinkedList
- BitArray
- ConcurrentBag
- ListDictionary
- HybridDictionary
- Channels
- PriorityQueue
- BlockingCollection
常用集合
数组
--空数组
Enumerable.Empty<int>().ToArray();
new List<int>().ToArray();
int[] arr = { 1, 2 };
int[] array = new int[] { 10, 20, 30 };
int[] array = new [] { 10, 20, 30 };
arr.Append(3);//添加
Array.Find(arr,i => i == 1);//查找某个元素
arr= Array.FindAll(arr, i => i != 1).ToArray();//删除
Console.WriteLine(String.Join(",", arr));//以逗号间隔输出数组
ArrayList
ArrayList list = new ArrayList();
list.Add(10);//单个添加
foreach (int number in new int[5] { 1, 2, 3, 4, 5 })
{
list.Add(number);//循环添加一个数组
}
int[] number2 = new int[2] { 11, 12 };
list.AddRange(number2);//集体添加
list.Remove(3);//删除值为3的
list.RemoveAt(3);//移除下标为3的
ArrayList list2 = new ArrayList(list.GetRange(1, 3));//新ArrayList(list2)只取旧ArrayList(list)中的一部份List<T>.GetRange(Index, Count)从下标为1的开始取三个
Console.WriteLine("Method One:");
foreach (int i in list)
{
Console.WriteLine(i);//遍历方法一
}
Console.WriteLine("Method Two:");
for (int i = 0; i != list2.Count; i++)//数组是length
{
int number = (int)list2[i];//一定要强制转换
Console.WriteLine(number);//遍历方法二
}
BitArray
BitArray 类管理一个紧凑型的位值数组,它使用布尔值来表示,其中 true 表示位是开启的(1),false 表示位是关闭的(0)。当您需要存储位,但是事先不知道位数时,则使用点阵列。您可以使用整型索引从点阵列集合中访问各项,索引从零开始。
// 创建两个大小为 8 的点阵列
BitArray ba1 = new BitArray(8);
BitArray ba2 = new BitArray(8);
byte[] a = { 60 };
byte[] b = { 13 };
// 把值 60 和 13 存储到点阵列中
ba1 = new BitArray(a);
ba2 = new BitArray(b);
// ba1 的内容
Console.WriteLine("Bit array ba1: 60");
for (int i = 0; i < ba1.Count; i++)
{
Console.Write("{0, -6} ", ba1[i]);
}
Console.WriteLine();
// ba2 的内容
Console.WriteLine("Bit array ba2: 13");
for (int i = 0; i < ba2.Count; i++)
{
Console.Write("{0, -6} ", ba2[i]);
}
Console.WriteLine();
BitArray ba3 = new BitArray(8);
ba3 = ba1.And(ba2);
// ba3 的内容
Console.WriteLine("Bit array ba3 after AND operation: 12");
for (int i = 0; i < ba3.Count; i++)
{
Console.Write("{0, -6} ", ba3[i]);
}
Console.WriteLine();
ba3 = ba1.Or(ba2);
// ba3 的内容
Console.WriteLine("Bit array ba3 after OR operation: 61");
for (int i = 0; i < ba3.Count; i++)
{
Console.Write("{0, -6} ", ba3[i]);
}
List
var list = new List<string> { "a", "c" };
字典
//New方法
var dicA = new Dictionary<int, string>
{
[1] = "a",
[5] = "e"
};
//Old方法
var dicB = new Dictionary<int, string>
{
{1, "a"},
{5, "b"}
};
//判断Key是否存在
dicA.ContainsKey(1);
//根据键获取值
dicA.GetValueOrDefault(1);
string stra = string.Empty;
dicA.TryGetValue(1, out stra);
//遍历字典
foreach (KeyValuePair<int, string> kvp in dicA)
{
Console.WriteLine(kvp.Key + kvp.Value);
}
//获取哈希表中键集合
Dictionary<int, string>.KeyCollection keyColl = dicA.Keys;
//获取哈希表值集合
Dictionary<int, string>.ValueCollection valueColl = dicA.Values;
//Linq获取第一个值并判断是否非空
KeyValuePair<int, string> result = dicA.FirstOrDefault(kv => kv.Key == 2);
if (!result.Equals(default(KeyValuePair<int, string>)))
{
Console.WriteLine("非空");
}
else
{
Console.WriteLine("等于空");
}
//转字典
Dictionary<string, string> dic = dt.AsEnumerable().ToDictionary(row => row["Id"].ToString(), row => row["Name"].ToString());
string[] str = new string[] { "Car", "Bus", "Bicycle" };
var d = str.ToDictionary(item => item, item => true);
//ToDictionary分组
var f= str.GroupBy(k=>k).ToDictionary(k => k.Key, v => v.Count());
//转字典
Dictionary<string, string> dic = dt.AsEnumerable().ToDictionary(row => row["Id"].ToString(), row => row["Name"].ToString());
string[] str = new string[] { "Car", "Bus", "Bicycle" };
var d = str.ToDictionary(item => item, item => true);
//ToDictionary分组
var f= str.GroupBy(k=>k).ToDictionary(k => k.Key, v => v.Count());
//转元祖字典
Dictionary<string, List<Tuple<string, string, string>>> dataDic = detail.AsEnumerable()
.GroupBy(row => row.Field<string>("SampleId"))
.ToDictionary(
group => group.Key,
group => group.Select(row => new Tuple<string, string, string>(
row["Code"].ToString(),
row["STR1"].ToString(),
row["STR9"].ToString()
)).ToList());
//List转字典,Key重复取第一条
tuples.GroupBy(tuple => tuple.Item2).ToDictionary(group => group.Key, group => group.First().Item1);
KeyValuePair
List<KeyValuePair<int, string>> pairs = new List<KeyValuePair<int, string>>();
pairs.Add(new KeyValuePair<int, string>(1, "apple"));
pairs.Add(new KeyValuePair<int, string>(2, "cherry"));
pairs.Add(new KeyValuePair<int, string>(2, "date")); // 重复的键
pairs.Add(new KeyValuePair<int, string>(3, "fig"));
pairs.Add(new KeyValuePair<int, string>(3, "grape")); // 重复的键
pairs.Add(new KeyValuePair<int, string>(4, "honeydew"));
pairs.Add(new KeyValuePair<int, string>(5, "kiwi"));
pairs.Add(new KeyValuePair<int, string>(5, "lemon")); // 重复的键
foreach (KeyValuePair<int, string> pair in pairs)
{
Console.WriteLine("Key: " + pair.Key + ", Value: " + pair.Value);
}
Hashtable
Hashtable 遍历是无序的
Hashtable ht = new Hashtable();
ht.Add("1", "hello");
ht.Add("2", "world");
ht.Add("3", "I");
ht.Add("4", "Love");
ht.Add("5", "China");
//遍历方法一:遍历哈希表中的键
foreach (string key in ht.Keys)
{
//Console.WriteLine(string.Format("{0}-{1}"), key, ht[key]);
Console.WriteLine(string.Format("{0}-{1}", key, ht[key]));
}
Console.WriteLine("**********************************************************");
//遍历方法二:遍历哈希表中的值
foreach (string value in ht.Values)
{
Console.WriteLine(value);
}
Console.WriteLine("**********************************************************");
//遍历方法三:遍历哈希表中的键值
foreach (DictionaryEntry de in ht)
{
Console.WriteLine(string.Format("{0}-{1}", de.Key, de.Value));
}
HashSet
HashSet是无序的
int[] arr = { 1, 2, 3 };
HashSet<int> hashSet = new HashSet<int>(arr);
hashSet.Add(4);
foreach (var city in hashSet)
{
Console.WriteLine(city);
}
//判断是否存在
hashSet.Contains(5);//false
//判断集合是否存在交集(类似Any)
int[] newarr = { 3, 4 };
hashSet.Overlaps(newarr);//true
//判断两个集合是否完全一致(顺序不对也是false)
HashSet<int> hashSet2 = new HashSet<int>(newarr);
hashSet.SetEquals(hashSet2);
//集合Join
HashSet<int> set1 = new HashSet<int> { 1, 2, 3, 4 };
HashSet<int> set2 = new HashSet<int> { 3, 4, 5, 6 };
//set1.UnionWith(set2);//1-6
//set1.ExceptWith(set2);//1,2
//set1.IntersectWith(set2);//3,4
//set1.SymmetricExceptWith(set2);//1,2,5,6
线程安全
//同步功能可以使HashTable(某种程度上)线程安全。这将在HashTable周围创建一个包装器,仅允许一个写入器和多个读取器访问HashTable。
//但是HashTable包装器不是完全线程安全的,一个线程可以迭代集合,而另一个线程仍然可以并发地更改集合,从而导致异常。
//创建一个同步(线程安全)的 Hashtable
Hashtable syncdHT = Hashtable.Synchronized(new Hashtable());
//判断是否线程安全
Console.WriteLine("myHT is {0}.", new Hashtable().IsSynchronized ? "synchronized" : "not synchronized");
Console.WriteLine("syncdHT is {0}.", syncdHT.IsSynchronized ? "synchronized" : "not synchronized");
Queue
队列(Queue)代表了一个先进先出的对象集合。enqueue方法入队列,dequeue方法出队列
Queue q = new Queue();
q.Enqueue('A');
q.Enqueue('B');
q.Enqueue('C');
q.Enqueue('D');
Console.WriteLine("Current queue: ");//队列先进先出
foreach (char value in q)
Console.Write(value + " ");
Console.WriteLine();
q.Enqueue('V');//向 Queue 的末尾添加一个对象。
q.Enqueue('H');
Console.WriteLine("Current queue: ");
foreach (char value in q)
Console.Write(value + " ");
Console.WriteLine();
Console.WriteLine("Removing some values ");
char ch = (char)q.Dequeue();//移除并返回在 Queue 的开头的对象。
Console.WriteLine("The removed value: {0}", ch);
ch = (char)q.Dequeue();
Console.WriteLine("The removed value: {0}", ch);
Stack
堆栈(Stack)代表了一个后进先出的对象集合。Push方法入栈,Pop方法出栈。
Stack st = new Stack();
st.Push('A');
st.Push('B');
st.Push('C');
st.Push('D');
Console.WriteLine("Current stack: ");//当前队列,先存后出
foreach (char value in st)
{
Console.Write(value + " ");
}
Console.WriteLine();
st.Push('V');//向 Stack 的顶部添加一个对象。
st.Push('H');
Console.WriteLine("The next poppable value in stack: {0}", st.Peek());//返回在 Stack 的顶部的对象,但不移除它。
Console.WriteLine("Current stack: ");
foreach (char value in st)
{
Console.Write(value + " ");
}
Console.WriteLine();
Console.WriteLine("Removing values ");
st.Pop();//移除并返回在 Stack 的顶部的对象
st.Pop();
st.Pop();
Console.WriteLine("Current stack: ");
foreach (char value in st)
{
Console.Write(value + " ");
}
LinkedList
//链表通常用于需要频繁插入和删除元素的场景,但不适用于需要随机访问元素的场景
LinkedList<string> list = new LinkedList<string>();
list.AddLast("apple");
list.AddLast("banana");
list.AddLast("cherry");
LinkedListNode<string> node = list.Find("banana");
list.AddBefore(node, "orange");
list.Remove(node);
foreach (string item in list)
{
Console.WriteLine(item);
}
Console.WriteLine(list.Count);
SortedList
SortedList sl = new SortedList();
sl.Add("1", "hello");
sl.Add("2", "world");
sl.Add("3", "I");
sl.Add("4", "Love");
foreach (var item in sl.Keys)
{
Console.WriteLine(item + ":" + sl[item]);
}
int myIndex = 1;
Console.WriteLine("The key at index {0} is {1}.", myIndex, sl.GetKey(myIndex));//获得下标为1的键的名称
Console.WriteLine("The value at index {0} is {1}.", myIndex, sl.GetByIndex(myIndex));//获得键为1的值
PriorityQueue
优先级出队
PriorityQueue<string, int> priorityQueue = new();
priorityQueue.Enqueue("Second", 2);
priorityQueue.Enqueue("Fourth", 4);
priorityQueue.Enqueue("Third 1", 3);
priorityQueue.Enqueue("Third 2", 3);
priorityQueue.Enqueue("First", 1);
while (priorityQueue.Count > 0)
{
string item = priorityQueue.Dequeue();
Console.WriteLine(item);
}
// Output:
// First
// Second
// Third 2
// Third 1
// Fourth
Channel
using Microsoft.IO;
using System.Threading.Channels;
namespace ConsoleApp1;
public class Program
{
static void Main(string[] args)
{
//不限容Channel
var channel = Channel.CreateUnbounded<int>();
//限容Channel
var channelBounded = Channel.CreateBounded<string>(new BoundedChannelOptions(1000) { FullMode = BoundedChannelFullMode.Wait });
}
public static async Task SingleProducerSingleConsumer()
{
var channel = Channel.CreateUnbounded<int>();
// 生产者写入消息
channel.Writer.TryWrite(1);
await channel.Writer.WriteAsync(2);
//生产者也可以明确告知消费者不会发送任何消息了
channel.Writer.Complete();
//当有空间可写时,返回一个true。因为Channel有限容类型的Channel,所以这个方法也可以作为一个屏障,当Channel空间已满时,进行阻塞
if (await channel.Writer.WaitToWriteAsync()) { }
//async stream,在没有被生产者明确Complete的情况下,这里会一致阻塞下去
await foreach (var item in channel.Reader.ReadAllAsync())
{
Console.WriteLine(item);
}
}
public static async Task SingleProducerSingleConsumer2()
{
var channel = Channel.CreateUnbounded<int>();
Task.Run(async () =>
{
for (int i = 0; i < 10; i++)
{
await channel.Writer.WriteAsync(i);
if (i > 5)
{
channel.Writer.Complete();
}
}
});
Task.Run(async () =>
{
await foreach (var item in channel.Reader.ReadAllAsync())
{
Console.WriteLine(item);
}
});
}
public static async Task SingleProducerSingleConsumer3()
{
var channel = Channel.CreateUnbounded<int>();
var reader = channel.Reader;
for (int i = 0; i < 10; i++)
{
await channel.Writer.WriteAsync(i + 1);
}
while (await reader.WaitToReadAsync())
{
//var i2= await reader.ReadAsync();
if (reader.TryRead(out var i))
{
Console.WriteLine(i);
}
}
}
}
BlockingCollection
using System.Collections.Concurrent;
BlockingCollection<string> bc = new();
//先进先出(FIFO)
BlockingCollection<string> bc2 = new(new ConcurrentQueue<string>());
//先进后出(LIFO)
BlockingCollection<int> bc3 = new(new ConcurrentStack<int>());
//生产者
Task.Factory.StartNew(async () =>
{
int count = 0;
while (true)
{
bc.Add("String: " + count);
count++;
await Task.Delay(1000 * 5);
//if (count > 10)
//{
// bc.CompleteAdding(); //代表添加完成
//}
}
});
//消费者
Task.Factory.StartNew(async () =>
{
while (true)
{
foreach (var element in bc.GetConsumingEnumerable())
{
Console.WriteLine("Work: " + element);
}
await Task.Delay(1000 * 5);
}
});
元组
元组不是集合
var user = ("小红", 18);
Console.WriteLine($"Name:{user.Item1}, Age:{user.Item2}");
var userDetails = (Age: 30, Name: "Ben", TestScore: 50f);
//ValueTuple是值类型,Tuple是引用类型
Tuple<string, int> tuple = new Tuple<string, int>("小红", 18);
ValueTuple<string, int> valueTuple = new ValueTuple<string, int>("小红", 18);
//集合
List<Tuple<string, int>> _tuples=new List<Tuple<string, int>>();
_tuples.Add(new Tuple<string, int> ( "", 1 ));
Span
转换
string[] arr = { "a" };
//List直接转换
var span = System.Runtime.InteropServices.CollectionsMarshal.AsSpan(arr.ToList());
//数组直接转换
var span2 = arr.AsSpan();
使用
foreach (var item in CollectionsMarshal.AsSpan(_list)) { }
for (int i = 0; i < span.Length; i++) { _ = span[i]; }
请注意,在使用过程List或数组中不应添加和删除对象。
集合常用方法
常用
//判断一个string集合的字符串是否包含另一个集合的某一个元素
List<string> list1 = new List<string> { "apple", "banana", "orange" };
List<string> list2 = new List<string> { "an", "ra", "ge" };
bool isContain = list1.Any(str => list2.Any(subStr => str.Contains(subStr)));
排序
排序
myList = myList.OrderBy(c => c.Code).ToList();
myList.Sort((p1, p2) => string.Compare(p1.Name, p2.Name));
myList.Sort((p1, p2) => p1.Age.CompareTo(p2.Age));
倒序
myList = myList.OrderByDescending(c => c.Code).ToList();
myList.Sort((p1, p2) => string.Compare(p2.Name, p1.Name));
数组关联查询
int[] arrA = { 1, 2, 3 };
int[] arrB = { 2, 4 };
var Result1 = arrA.Union(arrB); //1234
var Result2 = arrA.Concat(arrB); //12324
var Result3 = arrA.Intersect(arrB); //2
var Result4 = arrA.Except(arrB); //13
var Result5 = arrA.Except(arrB).Union(arrB.Except(arrA));//134
Take/Skip
int[] arr = { 0, 1, 2, 3, 4, 5 };
Console.WriteLine(string.Join(',',arr.Take(2))); //0,1
Console.WriteLine(string.Join(',', arr.Skip(2))); //2,3,4,5
Console.WriteLine(string.Join(',', arr.TakeLast(2))); //4,5
Console.WriteLine(string.Join(',', arr.SkipLast(2))); //0,1,2,3
var source= Enumerable.Range(1, 10);
source.ElementAt(^2); // returns 9
var xx = source.Take(7).Skip(2).ToList(); // returns 34567
//source.Take(..3) 代替 source.Take(3)
//source.Take(3..) 代替 source.Skip(3)
//source.Take(2..7) 代替 source.Take(7).Skip(2)
//source.Take(^3..) 代替 source.TakeLast(3)
//source.Take(..^3) 代替 source.SkipLast(3)
//source.Take(^7..^3)而不是.source.TakeLast(7).SkipLast(3)
分页
var arr = Enumerable.Range(1, 100);
int pageindex = 3;
int pageSize = 5;
var items = arr.Skip((pageindex - 1) * pageSize).Take(pageSize);
foreach (var book in items)
Console.WriteLine(book);
long pageCount = (long)Math.Ceiling(arr.LongCount() * 1.0 / pageSize);
Console.WriteLine("总页数" + pageCount);
EF Core分页
// <summary>
/// 分页方法
/// </summary>
/// <param name="pageindex">页码从1开始</param>
/// <param name="pageSize">每一页的数据条数</param>
static void printpage(int pageindex, int pageSize)
{
using (MydatabaseContext mydatabase = new MydatabaseContext())
{
//过滤到不想要的数据
//Contains()可以用来判断序列中是否存在指定的元素。
//过滤掉不行要的数据
IQueryable<TBook> books = mydatabase.TBooks.Where(a => !a.Bookname.Contains("李四"));
//减一是因为要从零开始
var items = books.Skip((pageindex - 1) * pageSize).Take(pageSize);
foreach (var book in items)
{
Console.WriteLine(book.Bookname);
}
long count = books.LongCount();
long pageCount = (long)Math.Ceiling(count * 1.0 / pageSize);
Console.WriteLine("总页数" + pageCount);
}
}
TakeWhile/SkipWhile
int[] nums = { 20, 15, 7, 11, 13, 4, 9 };
//获取第一个小于条件外的元素及后面的元素
//案例中25和15在条件内,不会获取到,7在条件外,会获取7及其后面所有元素
var result = nums.SkipWhile(n => n > 10);
foreach (var num in result)
Console.WriteLine(num);
//获取开始部分到条件内的数据,当遇到第一个条件外元素时,后面元素不再判断
//案例中 123 在条件内,4因为不在条件内,4和后面元素都不会获取
var intList = new int[] { 1, 2, 3, 4, 5, -1, -2 };
var list = intList.TakeWhile(x => x <= 3);
foreach (var i in list)
Console.WriteLine(i);
//i为元素坐标
var newList1 = intList.TakeWhile((p, i) => p <= 3 && i < 2);
Enumerable常用方法
Range/Repeat/Empty
//1,2,3...100
var a=Enumerable.Range(1,100).ToList();
//新建空对象
var b=Enumerable.Empty<int>().AsQueryable();
//添加重复数据
IEnumerable<int> ints = Enumerable.Repeat(1, 10);
//输出 1 1 1 1 1 1 1 1 1 1
foreach (int i in ints) Console.WriteLine(i);
Append/Prepend
- Append:向序列的尾部添加一个值。
- Prepend:向序列的开头添加一个值。
var arr = Enumerable.Range(1, 2);
arr = arr.Append(3);
arr = arr.Prepend(4);
//4123
foreach (int i in arr) Console.WriteLine(i);
Index
//获取值的索引,获取索引值
var arr = new int[] { 1, 2, 3 };
var val = arr[1];
var index = Array.IndexOf(arr, 2);
var index2 = Array.LastIndexOf(arr, 2);
int index3 = Array.FindIndex(arr, (a) => a == 2);
int index4 = Array.FindLastIndex(arr, (a) => a == 2);
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
int index5 = list.IndexOf(3);
//IEnumerable没有IndexOf方法,可以通过Array.IndexOf获取值的索引
var enumerable = Enumerable.Range(1, 20);
int value2 = enumerable.ElementAt(5);
var index6 = Array.IndexOf(enumerable.ToArray(), 2);
var arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var list = arr.ToList();
var index = list.IndexOf(5);
var index2 = list.FindIndex(X => X == 2);
list.GetRange(index, list.Count - index);//56789
list.GetRange(index + 1, list.Count - index - 1);//6789
list.GetRange(0, index);//1234
list.GetRange(0, index + 1);//12345
list.RemoveRange(0, index);//删除1234
Cast/OfType
ArrayList al = new ArrayList { 1, 2, "a" };
//会抛出异常
IEnumerable<int> IEInt = al.Cast<int>();
//自动移除无法转换的元素
IEnumerable<int> IEOfType = al.OfType<int>();
//输出 1 2
foreach (int i in IEOfType) Console.WriteLine(i);
Reverse
反转集合元素
var arr = Enumerable.Range(1, 5);
arr = arr.Reverse();
//54321
foreach (int i in arr) Console.Write(i);
Chunk
切片
// { {0,1,2}, {3,4,5}, {6,7,8}, {9} }
List<int[]> list = Enumerable.Range(1, 10).Chunk(3).ToList();
实现方法
public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize)
{
while (source.Any())
{
yield return source.Take(chunksize);
source = source.Skip(chunksize);
}
}
ZIP
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
var numbersAndWords = words.Zip(numbers, (first, second) => first + " " + second);
var caxz = numbersAndWords.ToList();
var xs = Enumerable.Range(1, 10);
var ys = xs.Select(x => x.ToString());
var zs = xs.Select(x => x % 2 == 0);
foreach ((int x, string y, bool z) in Enumerable.Zip(xs, ys, zs)) { }
SequenceEqual
判断两个集合是否相等
IList<string> strList1 = new List<string>() { "One", "Two", "Three", "Four", "Three" };
IList<string> strList2 = new List<string>() { "One", "Two", "Three", "Four", "Three" };
bool isEqual = strList1.SequenceEqual(strList2); // returns true
IList<string> strList3 = new List<string>() { "One", "Two", "Three", "Four", "Three" };
IList<string> strList4 = new List<string>() { "Two", "One", "Three", "Four", "Three" };
bool isEqual2 = strList1.SequenceEqual(strList2); // returns false
SelectMany
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp2
{
internal class Program
{
static void Main(string[] args)
{
List<Person> personList = new List<Person> {
new Person{
Name = "P1", Age = 18, Gender = "Male",
Dogs = new Dog[] {
new Dog { Name = "D1" },
new Dog { Name = "D2" }
}
},
new Person{
Name = "P2", Age = 19, Gender = "Male",
Dogs = new Dog[]{
new Dog { Name = "D3" }
}
},
new Person{
Name = "P3", Age = 17,Gender = "Female",
Dogs = new Dog[]{
new Dog { Name = "D4" },
new Dog { Name = "D5" },
new Dog { Name = "D6" }
}
}
};
var dogs1 = personList.SelectMany(p => p.Dogs);
var dogs2 = personList.SelectMany((p, i) =>
p.Dogs.Select(d =>
{
d.Name = $"{i},{d.Name}";
return d;
}));
var results1 = personList.SelectMany(p => p.Dogs, (p, d) => new { PersonName = p.Name, DogName = d.Name });
var results2 = personList.SelectMany((p, i) =>
{
for (int j = 0; j < p.Dogs.Length; j++)
{
p.Dogs[j].Name = $"{i}-{p.Dogs[j].Name}";
}
return p.Dogs;
}, (p, d) => new { PersonName = p.Name, DogName = d.Name });
}
}
class Person
{
public string Name { set; get; }
public int Age { set; get; }
public string Gender { set; get; }
public Dog[] Dogs { set; get; }
}
public class Dog
{
public string Name { set; get; }
}
}
ThenBy
LINQ中的排序操作符,包括:OrderBy、OrderByDescending、ThenBy、ThenByDescending、Reverse,提供了升序或者降序排序。
- OrderBy:按升序对序列的元素进行排序。
- OrderByDescending:按降序对序列的元素排序。
- ThenBy:按升序对序列中的元素执行后续排序。
- ThenByDescending:按降序对序列中的元素执行后续排序。
List<Employee> result = new List<Employee>
{
new Employee() { Name = "张伟伟", DeptID = 3, DeptName = "市场部", Salary = 1500, EntryTime = DateTime.Parse("2016-05-12") },
new Employee() { Name = "李涛涛", DeptID = 2, DeptName = "财务部", Salary = 1600, EntryTime = DateTime.Parse("2017-02-16") },
new Employee() { Name = "王亮亮", DeptID = 1, DeptName = "研发部", Salary = 1900, EntryTime = DateTime.Parse("2018-10-25") },
new Employee() { Name = "孙红红", DeptID = 1, DeptName = "研发部", Salary = 1900, EntryTime = DateTime.Parse("2018-08-03") },
new Employee() { Name = "黄苗苗", DeptID = 3, DeptName = "市场部", Salary = 2200, EntryTime = DateTime.Parse("2016-09-06") },
new Employee() { Name = "蔡明明", DeptID = 1, DeptName = "研发部", Salary = 3500, EntryTime = DateTime.Parse("2012-11-25") },
new Employee() { Name = "吴慧慧", DeptID = 2, DeptName = "财务部", Salary = 1800, EntryTime = DateTime.Parse("2018-07-26") },
new Employee() { Name = "杨梅梅", DeptID = 3, DeptName = "市场部", Salary = 2200, EntryTime = DateTime.Parse("2017-02-15") }
};
//先按照部门ID排序,在按照薪资排序
result = result.OrderBy(a => a.DeptID).ThenByDescending(a => a.Salary).ThenBy(a => a.EntryTime).ToList();
/// <summary>
/// 员工信息类
/// </summary>
public class Employee
{
/// <summary>
/// 员工名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 部门编号
/// </summary>
public int DeptID { get; set; }
/// <summary>
/// 部门名称
/// </summary>
public string DeptName { get; set; }
/// <summary>
/// 薪资
/// </summary>
public decimal Salary { get; set; }
/// <summary>
/// 入职时间
/// </summary>
public DateTime EntryTime { get; set; }
}
ToLookup
List<Student> list = new List<Student>() {
new Student() { Id = 1, Age = 1, Name = "11" },
new Student() { Id = 1, Age = 2, Name = "22" },
new Student() { Id = 2, Age = 2, Name = "22"},
new Student() { Id = 2, Age = 3, Name = "33" },
new Student() {Id = 2, Age = 4, Name = "44" },
new Student() { Id = 3, Age = 3, Name = "33" },
new Student() { Id = 4, Age = 3, Name = "33" },
new Student() { Id = 4, Age = 5, Name = "33" },
};
var dic = list.ToLookup(m => m.Id);
foreach (var item in dic)
{
Console.WriteLine("学生ID号:" + item.Key);
foreach (var item1 in item)
{
Console.WriteLine("\t\t" + item1 + " || " + item1.Age + " || " + item1.Name);
}
}
//输出:
//学生ID号: 1
// Student || 1 || 11
// Student || 2 || 22
//学生ID号: 2
// Student || 2 || 22
// Student || 3 || 33
// Student || 4 || 44
//学生ID号: 3
// Student || 3 || 33
//学生ID号: 4
// Student || 3 || 33
// Student || 5 || 33
public class Student
{
public int Id { get; set; }
public int Age { get; set; }
public string Name { get; set; }
}