Linq是结合了声明式的命令式结构
语法
引入using System.Linq; linq的核心就是一段查询数据
//声明式结构
var query = from file in new DirectoryInfo(path).GetFiles()
orderby file.Length descending
select file;
//命令式结构,使用对象的链式结构完成
var query = new DirectoryInfo(path).GetFiles()
.OrderByDescending(f => f.Length)
.Take(5);
foreach (var f in query)
{
Console.WriteLine($"{f.Name,-20} : {f.Length,10:N}");
}
lambda 表达式
匿名方法
delegate (参数)=>{逻辑处理;}
//
()=>{}
Linq查询
引入Linq后,就可以在各种集合中以对象的形式使用linq的方法 .orderby .when .count(Linq的方法查询) Linq的结构化查询(类sql)
var query = from c in customers
where c.Address == "广州"
orderby c.Name
select c.Name;
//对象结构
var query = customers
.Where(c => c.Address == "广州")
.OrderBy(c => c.Name);
//对象结构中,如果最后的c不需要做数据塑形,select可以忽略
//.Select(c => c);
where的实现原理
//不需要实例化就可使用,故用static
public static MyLinq{
//集合需要进行迭代操作,故使用IEumerable
// 因为要用到链式结构,所以第一个对象(数据源)就是它本身, 第二个参数要接受一个委托方法
public static IEnumerable<T> MyWhere<T>(this IEumerable<T> source, Func<T,bool> predicate){
var result = new List<T>();
foreach(var item in source){
//遍历所有数据,符合条件的返回
if(predicate(item)){
result.Add(item);
}
}
return result
}
}
//实际上where是延迟执行(yield return)所以更像这样
foreach(var item in source){
//遍历所有数据,符合条件的返回
if(predicate(item)){
yield return item;
}
}
从CSV中读取数据
首先根据csv中数据创建数据模型
static void Main(string[] args)
{
List<Car> cars = ProcessCars("fuel.csv");
Console.Read();
}
private static List<Car> ProcessCars(string v)
{
var result = File.ReadAllLines(v)
.Skip(1)
.Where(l => l.Length > 1)
.Select(line =>
{
var columns = line.Split(",");
return new Car
{
Year = columns[0],
Manufacturer = columns[1],
Model = columns[2],
Displacement = double.Parse(columns[3]),
CylindersCount = int.Parse(columns[4]),
City = int.Parse(columns[5]),
Highway = int.Parse(columns[6]),
Combined = int.Parse(columns[7])
};
});
//这里需要调用ToList让它变成IEumerable
return result.ToList();
}
排序
对次一级排序时,不能连续使用orderby,连续使用orderby会给列表重新排序
var query = cars
//按照降序排序
.OrderByDescending(c => c.Combined)
//对次一级排序
.ThenByDescending(c => c.Model);
//声明式语法
var query = (from car in cars
where car.Manufacturer == "dddddd" && car.Year == "2016"
//只需要将两个排序条件逗号分隔,编译器会自动识别一级和二级
orderby car.Combined descending, car.Model descending
select car)
//.First()
.FirstOrDefault();
//使用take(1),返回仍然是集合,但是集合只有一个元素,.First() .FirstOrDefault(); 返回的是对象 这两个方法可以在提取第一项数据的同时展开集合
数据量化 Any、All、Contains
Any(lambda表达式) 查询数据中是否含有某一类,返回一个bool值,一般与if搭配,any也可以判断一个集合是否为空,此时不需要传参 Contains(实例对象) 查询数据中是否有某某对象 All(lambda) 与Any相反,查询数据中是否全部满足条件,返回一个bool值
//Any()
var query2 = cars.Any(c => c.Manufacturer == "Volkswagen");
Console.WriteLine(query2);
if(query2)
{
Console.WriteLine("有大众");
}
else
{
Console.WriteLine("没有大众");
}
var isCarsEmpty = cars.Any();
// contains
var isReal = cars.Contains(query);
//All
var query2 = cars.All(c => c.Manufacturer == "Volkswagen");
数据投影(select)
数据投影 将有用的信息投影出来,避免冗余信息
select new {
Model = car.Model,
Combined = car.Combined
})
selectMany展开嵌套集合,并且提取子集合中所有数据
//此时query类型是字符(从字符串即字符的集合中取出数据)
var query3 = cars.SelectMany(c => c.Model);
foreach(var c in query3)
{
Console.WriteLine(c);
}
数据连接 join
join与from作用类似,告诉linq从哪读取数据 join on 语法中不能使用==,用equals,只能判断是否相等,不能比大小
var query = (from car in cars
join manufacturer in manufacturers on car.Manufacturer equals manufacturer.Name
orderby car.Combined descending, car.Model descending
select new
{
Manufacturer = car.Manufacturer,
Model = car.Model,
Combined = car.Combined,
Headquarters = manufacturer.Headquarters,
Phone = manufacturer.Phone
})
.Take(10);
//对象的链式调用
// 两个lambda表达式 用于表示链接的内容,第三个表示链接后内容最终输出形式
var query2 = cars.Join(manufacturers, (c) => c.Manufacturer, (m) => m.Name, (c, m) => new
{
Car = c,
Manufacturer = m
}).OrderByDescending(joinData => joinData.Car.Combined)
.ThenBy(joinData => joinData.Car.Model)
.Select(joinData => new
{
Manufacturer = joinData.Car.Manufacturer,
Model = joinData.Car.Model,
Combined = joinData.Car.Combined,
Headquarters = joinData.Manufacturer.Headquarters,
Phone = joinData.Manufacturer.Phone
}).Take(10);
join对应于sql中的内链接:任何数据只要在任意数据源中缺失,将会忽略整个数据的输出
数据分组 group
group和select一样都是进行数据投影的过程,故可以直接用于结尾
var query = from car in cars
group car by car.Manufacturer into manufacturerGroup
orderby manufacturerGroup.Key descending
select manufacturerGroup;
var query = from car in cars
group car by car.Manufacturer into manufacturerGroup
orderby manufacturerGroup.Key descending
select manufacturerGroup;
数据分组连接 group join
在分组过程中使用第二个数据源
var query = from manufacturer in manufacturers
join car in cars on manufacturer.Name equals car.Manufacturer into carGroup
orderby manufacturer.Name descending
select new
{
Manufacturer = manufacturer,
Cars = carGroup
};
var query2 = manufacturers.GroupJoin(cars, m => m.Name, c => c.Manufacturer, (m, carGroup) => new
{
Manufacturer = m,
Cars = carGroup
}).OrderByDescending(m => m.Manufacturer.Name);
数据聚合
var query = from car in cars
group car by car.Manufacturer into carGroup
select new
{
Manufacturer = carGroup.Key,
Avg = carGroup.Average(c => c.Combined),
Max = carGroup.Max(c => c.Combined),
Min = carGroup.Min(c => c.Combined)
} into tempGroup
//根据Avg排序
orderby tempGroup.Avg descending
select tempGroup;
foreach (var group in query)
{
Console.WriteLine($"{group.Manufacturer} 油耗情况 ");
Console.WriteLine($"\t 最高: {group.Max}");
Console.WriteLine($"\t 最低: {group.Min}");
Console.WriteLine($"\t 平均: {group.Avg}");
}