C# LINQ学习笔记三:LINQ to OBJECT之操作字符串
本笔记摘抄自:https://www.cnblogs.com/liqingwen/p/5814204.html,记录一下学习过程以备后续查用。
一、统计单词在字符串中出现的次数
请注意,若要执行计数,请先调用Split方法来创建词数组。Split方法存在性能开销,如果对字符串执行的唯一操作是计数词,则应考虑改用Matches或
IndexOf方法。
class Program
{
static void Main(string[] args)
{
#region LINQ 统计单词在字符串中出现的次数
const string text = @"Historically, the world of data and the world of objects" +
@" have not been well integrated. Programmers work in C# or Visual Basic" +
@" and also in SQL or XQuery. On the one side are concepts such as classes," +
@" objects, fields, inheritance, and .NET Framework APIs. On the other side" +
@" are tables, columns, rows, nodes, and separate languages for dealing with" +
@" them. Data types often require translation between the two worlds; there are" +
@" different standard functions. Because the object world has no notion of query, a" +
@" query can only be represented as a string without compile-time type checking or" +
@" IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to" +
@" objects in memory is often tedious and error-prone.";
const string searchWord = "data"; //字符串转换成数组
var source = text.Split(new[] { '.', '?', '!', ' ', ';', ':', ',' }, StringSplitOptions.RemoveEmptyEntries); //创建查询,并忽略大小写比较。
var query = from word in source
where string.Equals(word, searchWord, StringComparison.InvariantCultureIgnoreCase)
select word; //统计匹配数量
var wordCount = query.Count();
Console.WriteLine($"{wordCount} occurrences(s) of the search word \"{searchWord}\" were found.");
Console.Read();
#endregion
}
}
运行结果如下:
二、查询包含指定一组单词的句子
此示例演示如何查找文本文件中包含指定一组单词中每个单词匹配项的句子。虽然在此示例中搜索条件数组是硬编码的,但也可以在运行时动态填充此
数组。
class Program
{
static void Main(string[] args)
{
#region LINQ 查询包含指定一组单词的句子
const string text = @"Historically, the world of data and the world of objects " +
@"have not been well integrated. Programmers work in C# or Visual Basic " +
@"and also in SQL or XQuery. On the one side are concepts such as classes, " +
@"objects, fields, inheritance, and .NET Framework APIs. On the other side " +
@"are tables, columns, rows, nodes, and separate languages for dealing with " +
@"them. Data types often require translation between the two worlds; there are " +
@"different standard functions. Because the object world has no notion of query, a " +
@"query can only be represented as a string without compile-time type checking or " +
@"IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to " +
@"objects in memory is often tedious and error-prone."; //将文本块切割成数组
var sentences = text.Split('.', '?', '!'); //定义搜索条件,此列表可以在运行时动态添加。
string[] wordsToMatch = { "Historically", "data", "integrated" }; var query = from sentence in sentences
let t = sentence.Split(new char[] { '.', '?', '!', ' ', ';', ':', ',' }, StringSplitOptions.RemoveEmptyEntries)
where t.Distinct().Intersect(wordsToMatch).Count() == wordsToMatch.Length //去重,取交集后的数量对比。
select sentence; foreach (var sentence in query)
{
Console.WriteLine(sentence);
}
Console.Read();
#endregion
}
}
运行结果如下:
查询运行时首先将文本拆分成句子,然后将句子拆分成包含每个单词的字符串数组。对于每个这样的数组,Distinct<TSource> 方法移除所有重复的单词,
然后查询对单词数组和wordstoMatch数组执行Intersect<TSource>操作。如果交集的计数与wordsToMatch数组的计数相同,则在单词中找到了所有的单词,
然后返回原始句子。
在对Split的调用中,使用标点符号作为分隔符,以从字符串中移除标点符号。如果您没有这样做,则假如您有一个字符串“Historically,”,该字符串不会
与wordsToMatch数组中的“Historically”相匹配。根据源文本中标点的类型,您可能必须使用其他分隔符。
三、在字符串中查询字符
因为String类实现泛型IEnumerable<T>接口,所以可以将任何字符串作为字符序列进行查询。但是,这不是LINQ的常见用法。若要执行复杂的模式匹配操
作,请使用Regex类。
下面的示例查询一个字符串以确定它包含的数字的数目。
class Program
{
static void Main(string[] args)
{
#region LINQ 在字符串中查询字符
const string source = "ABCDE99F-J74-12-89A"; //只选择数字的字符
var digits = from character in source
where char.IsDigit(character)
select character;
Console.Write("Digit:");
foreach (var digit in digits)
{
Console.Write($"{digit} ");
}
Console.WriteLine(); //选择第一个"-"之前的所有字符
var query = source.TakeWhile(x => x != '-');
foreach (var character in query)
{
Console.Write(character);
} Console.Read();
#endregion
}
}
运行结果如下:
四、正则表达式结合LINQ查询
此示例演示如何使用Regex类创建正则表达式以便在文本字符串中进行更复杂的匹配。使用LINQ查询可以方便地对您要用正则表达式搜索的文件进行准确
筛选以及对结果进行加工。
class Program
{
static void Main(string[] args)
{
#region LINQ 正则表达式结合LINQ查询
//请根据不同版本的VS进行路径修改
const string floder = @"C:\Program Files (x86)\Microsoft Visual Studio\";
var fileInfoes = GetFiles(floder);
//创建正则表达式来寻找所有的"Visual"
var searchTerm = new Regex(@"http://(www.w3.org|www.npmjs.org)"); //搜索每一个“.html”文件
//通过where找到匹配项
//注意:select中的变量要求显示声明其类型,因为MatchCollection不是泛型IEnumerable集合。
var query = from fileInfo in fileInfoes
where fileInfo.Extension == ".html"
let text = File.ReadAllText(fileInfo.FullName)
let matches = searchTerm.Matches(text)
where matches.Count >
select new
{
name = fileInfo.FullName,
matchValue = from Match match in matches select match.Value
}; Console.WriteLine($"The term \"{searchTerm}\" was found in:");
Console.WriteLine();
foreach (var q in query)
{
//修剪匹配找到的文件中的路径
Console.WriteLine($"name==>{q.name.Substring(floder.Length - 1)}");
//输出找到的匹配值
foreach (var v in q.matchValue)
{
Console.WriteLine($"matchValue==>{v}");
}
//输出空白行
Console.WriteLine();
}
Console.Read();
#endregion
} /// <summary>
/// 获取指定路径的文件信息
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private static IList<FileInfo> GetFiles(string path)
{
var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories); return files.Select(file => new FileInfo(file)).ToList();
}
}
运行结果如下:
五、查找两个集合间的差异
此示例演示如何使用LINQ对两个字符串列表进行比较,并输出那些位于text1.txt中但不在text2.txt中的行。
Bankov, Peter
Holm, Michael
Garcia, Hugo
Potra, Cristina
Noriega, Fabricio
Aw, Kam Foo
Beebe, Ann
Toyoshima, Tim
Guy, Wey Yuan
Garcia, Debra
text1.txt
Liu, Jinghao
Bankov, Peter
Holm, Michael
Garcia, Hugo
Beebe, Ann
Gilchrist, Beth
Myrcha, Jacek
Giakoumakis, Leo
McLin, Nkenge
El Yassir, Mehdi
text2.txt
class Program
{
static void Main(string[] args)
{
#region LINQ 查找两个集合间的差异
//创建数据源
var text1 = File.ReadAllLines(@"..\..\text1.txt");
var text2 = File.ReadAllLines(@"..\..\text2.txt"); //创建查询,这里必须使用方法语法。
var query = text1.Except(text2); //执行查询
Console.WriteLine("The following lines are in text1.txt but not text2.txt");
foreach (var name in query)
{
Console.WriteLine(name);
}
Console.Read();
#endregion
}
}
运行结果如下:
注:某些类型的查询操作(如 Except<TSource>、Distinct<TSource>、Union<TSource> 和 Concat<TSource>)只能用基于方法的语法表示。
六、排序或过滤任意单词或字段的文本数据
下面的示例演示如何按结构化文本(如逗号分隔值)行中的任意字段对该文本行进行排序,可在运行时动态指定该字段。
假定scores.csv中的字段表示学生的ID号,后面跟着四个测验分数。
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
scores.csv
class Program
{
static void Main(string[] args)
{
#region LINQ 排序或过滤任意单词或字段的文本数据
//创建数据源
var scores = File.ReadAllLines(@"..\..\scores.csv");
//可以改为0~4的任意值
const int sortIndex = ;
//演示从方法返回查询变量,非查询结果。
foreach (var score in SplitSortQuery(scores, sortIndex))
{
Console.WriteLine(score);
}
Console.Read();
#endregion
} /// <summary>
/// 分割字符串排序
/// </summary>
/// <param name="scores"></param>
/// <param name="num"></param>
/// <returns></returns>
private static IEnumerable<string> SplitSortQuery(IEnumerable<string> scores, int num)
{
var query = from line in scores
let fields = line.Split(',')
orderby fields[num] descending
select line;
return query;
}
}
运行结果如下:
七、对一个分割的文件的字段重新排序
逗号分隔值 (CSV) 文件是一种文本文件,通常用于存储电子表格数据或其他由行和列表示的表格数据。通过使用Split方法分隔字段,可以非常轻松地使用
LINQ来查询和操作CSV文件。事实上,可以使用此技术来重新排列任何结构化文本行部分。此技术不局限于CSV文件。
在下面的示例中,假定有三列分别代表学生的“姓氏”、“名字”和“ID”,这些字段基于学生的姓氏按字母顺序排列。查询生成一个新序列,其中首先出现的是
ID列,后面的第二列组合了学生的名字和姓氏。根据ID字段重新排列各行,结果保存到新文件,但不修改原始数据。
Adams,Terry,
Fakhouri,Fadi,
Feng,Hanying,
Garcia,Cesar,
Garcia,Debra,
Garcia,Hugo,
Mortensen,Sven,
O'Donnell,Claire,112
Omelchenko,Svetlana,
Tucker,Lance,
Tucker,Michael,
Zabokritski,Eugene,
spread.csv
class Program
{
static void Main(string[] args)
{
#region LINQ 对一个分割的文件的字段重新排序
//数据源
var lines = File.ReadAllLines(@"..\..\spread.csv");
//将旧数据的第2列的字段放到第一位,逆向结合第0列和第1列的字段。
var query = from line in lines
let t = line.Split(',')
orderby t[]
select $"{t[2]} {t[1]} {t[0]}"; foreach (var item in query)
{
Console.WriteLine(item);
}
Console.Read();
#endregion
}
}
运行结果如下:
八、组合和比较字符串集合
此示例演示如何合并包含文本行的文件,然后排序结果。具体来说,此示例演示如何对两组文本行执行简单的串联、联合和交集。
注:text1.txt及text2.txt与五、的一致。
class Program
{
static void Main(string[] args)
{
#region LINQ 组合和比较字符串集合
var text1 = File.ReadAllLines(@"..\..\text1.txt");
var text2 = File.ReadAllLines(@"..\..\text2.txt"); //简单连接并排序,重复保存。
var concatQuery = text1.Concat(text2).OrderBy(x => x);
OutputQueryResult(concatQuery, "Simple concatenate and sort,duplicates are preserved:"); //基于默认字符串比较器连接,并删除重名。
var unionQuery = text1.Union(text2).OrderBy(x => x);
OutputQueryResult(unionQuery, "Union removes duplicate names:"); //查找在两个文件中出现的名称
var intersectQuery = text1.Intersect(text2).OrderBy(x => x);
OutputQueryResult(intersectQuery, "Merge based on intersect:"); //在每个列表中找到匹配的字段,使用concat将两个结果合并,然后使用默认的字符串比较器进行排序。
const string nameMatch = "Garcia";
var matchQuery1 = from name in text1
let t = name.Split(',')
where t[] == nameMatch
select name;
var matchQuery2 = from name in text2
let t = name.Split(',')
where t[] == nameMatch
select name;
var temp = matchQuery1.Concat(matchQuery2).OrderBy(x => x);
OutputQueryResult(temp, $"Concat based on partial name match \"{nameMatch}\":"); Console.Read();
#endregion
} /// <summary>
/// 输出查询结果
/// </summary>
/// <param name="querys"></param>
/// <param name="title"></param>
private static void OutputQueryResult(IEnumerable<string> querys, string title)
{
Console.WriteLine(Environment.NewLine + title);
foreach (var query in querys)
{
Console.WriteLine(query);
}
Console.WriteLine($"Total {querys.Count()} names in list.");
}
}
运行结果如下:
九、从多个源中填充对象集合
不要尝试将内存中的数据或文件系统中的数据与仍在数据库中的数据相联接。此种跨域联接会生成未定义的结果,因为数据库查询和其他类型的源定义联
接运算的方式可能不同。另外,如果数据库中的数据量足够大,则存在此类运算引发内存不足异常的风险。若要将数据库数据与内存中的数据相联接,请首
先对数据库查询调用ToList或ToArray,然后对返回的集合执行联接。
class Program
{
static void Main(string[] args)
{
#region LINQ 从多个源中填充对象集合
//spread.csv每行包含姓氏、名字和身份证号,以逗号分隔。例如,Omelchenko,Svetlana,111
var names = File.ReadAllLines(@"..\..\spread.csv");
//scores.csv每行包括身份证号码和四个测试评分,以逗号分隔。例如,111,97,92,81,60
var scores = File.ReadAllLines(@"..\..\scores.csv"); //使用一个匿名的类型合并数据源。
//注:动态创建一个int的考试成绩成员列表。
//跳过分割字符串中的第一项,因为它是学生的身份证,不是一个考试成绩。
var students = from name in names
let t1 = name.Split(',')
from score in scores
let t2 = score.Split(',')
where t1[] == t2[]
select new
{
FirstName = t1[],
LastName = t1[],
ID = Convert.ToInt32(t1[]),
ExamScores = (from score in t2.Skip() select Convert.ToInt32(score)).ToList()
}; foreach (var student in students)
{
Console.WriteLine($"The average score of {student.FirstName} {student.LastName} is {student.ExamScores.Average()}.");
}
Console.Read();
#endregion
}
}
运行结果如下:
十、使用group将一个文件拆分成多个文件
此示例演示一种进行以下操作的方法:合并两个文件的内容,然后创建一组以新方式组织数据的新文件。
注:text1.txt及text2.txt与五、的一致。
class Program
{
static void Main(string[] args)
{
#region LINQ 使用group将一个文件拆分成多个文件
var text1 = File.ReadAllLines(@"..\..\text1.txt");
var text2 = File.ReadAllLines(@"..\..\text2.txt"); //并集:连接并删除重复的名字
var mergeQuery = text1.Union(text2);
//根据姓氏的首字母对姓名进行分组
var query = from name in mergeQuery
let t = name.Split(',')
group name by t[][] into g
orderby g.Key
select g; //注意嵌套的 foreach 循环
foreach (var g in query)
{
var fileName = @"testFile_" + g.Key + ".txt";
Console.WriteLine(g.Key + ":"); //写入文件
using (var sw = new StreamWriter(fileName))
{
foreach (var name in g)
{
sw.WriteLine(name);
Console.WriteLine(" " + name);
}
}
}
Console.Read();
#endregion
}
}
运行结果如下:
十一、向不同的文件中加入内容
此示例演示如何联接两个逗号分隔文件中的数据,这两个文件共享一个用作匹配键的共同值。如果您必须将两个电子表格的数据或一个电子表格和一个其
他格式的文件的数据组合为一个新文件,则此技术很有用,还可以修改此示例以适合任意种类的结构化文本。
class Program
{
static void Main(string[] args)
{
#region LINQ 向不同的文件中加入内容
var names = File.ReadAllLines(@"..\..\spread.csv");
var scores = File.ReadAllLines(@"..\..\scores.csv"); //该查询基于ID连接两个不同的电子表格
var query = from name in names
let t1 = name.Split(',')
from score in scores
let t2 = score.Split(',')
where t1[] == t2[]
orderby t1[]
select $"{t1[0]},{t2[1]},{t2[2]},{t2[3]},{t2[4]}"; //输出
OutputQueryResult(query, "Merge two spreadsheets:");
Console.Read();
#endregion
} /// <summary>
/// 输出查询结果
/// </summary>
/// <param name="querys"></param>
/// <param name="title"></param>
private static void OutputQueryResult(IEnumerable<string> querys, string title)
{
Console.WriteLine(Environment.NewLine + title);
foreach (var query in querys)
{
Console.WriteLine(query);
}
Console.WriteLine($"Total {querys.Count()} names in list.");
}
}
运行结果如下:
十二、计算一个CSV文本文件中的列值
此示例演示如何对.csv文件的列执行诸如Sum、Average、Min和Max等聚合计算,此示例可以应用于其他类型的结构化文本。
class Program
{
static void Main(string[] args)
{
#region LINQ 计算一个CSV文本文件中的列值
var scores = File.ReadAllLines(@"..\..\scores.csv"); //指定要计算的列
const int examNum = ; //+1表示跳过第一列
//统计单列
SingleColumn(scores, examNum + ); Console.WriteLine(); //统计多列
MultiColumns(scores); Console.Read();
#endregion
} /// <summary>
/// 统计单列
/// </summary>
/// <param name="lines"></param>
/// <param name="examNum"></param>
private static void SingleColumn(IEnumerable<string> lines, int examNum)
{
Console.WriteLine("Single Column Query:"); //查询步骤:
//1.分割字符串
//2.对要计算的列的值转换为int
var query = from line in lines
let t = line.Split(',')
select Convert.ToInt32(t[examNum]); //对指定的列进行统计
var average = query.Average();
var max = query.Max();
var min = query.Min(); Console.WriteLine($"Exam #{examNum}: Average:{average:##.##} High Score:{max} Low Score:{min}");
} /// <summary>
/// 统计多列
/// </summary>
/// <param name="lines"></param>
private static void MultiColumns(IEnumerable<string> lines)
{
Console.WriteLine("Multi Column Query:"); //查询步骤:
//1.分割字符串
//2.跳过ID列(第一列)
//3.将当前行的每个评分都转换成int,并选择整个序列作为一行结果。
var query1 = from line in lines
let t1 = line.Split(',')
let t2 = t1.Skip()
select (from t in t2 select Convert.ToInt32(t)); //执行查询并缓存结果以提高性能
var results = query1.ToList();
//找出结果的列数
var count = results[].Count(); //执行统计
for (var i = ; i < count; i++)
{
var query2 = from result in results
select result.ElementAt(i);
var average = query2.Average();
var max = query2.Max();
var min = query2.Min();
//#1表示第一次考试
Console.WriteLine($"Exam #{i + 1} Average: {average:##.##} High Score: {max} Low Score: {min}");
} }
}
运行结果如下:
C# LINQ学习笔记三:LINQ to OBJECT之操作字符串的更多相关文章
- MySql学习笔记三
MySql学习笔记三 4.DML(数据操作语言) 插入:insert 修改:update 删除:delete 4.1.插入语句 语法: insert into 表名 (列名1,列名2,...) val ...
- 学习笔记(三)--->《Java 8编程官方参考教程(第9版).pdf》:第十章到十二章学习笔记
回到顶部 注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.若有违本之,则本人不负法律责任.违法 ...
- openresty 学习笔记三:连接redis和进行相关操作
openresty 学习笔记三:连接redis和进行相关操作 openresty 因其非阻塞的调用,令服务器拥有高性能高并发,当涉及到数据库操作时,更应该选择有高速读写速度的redis进行数据处理.避 ...
- ZooKeeper学习笔记三:使用ZooKeeper实现一个简单的配置中心
作者:Grey 原文地址:ZooKeeper学习笔记三:使用ZooKeeper实现一个简单的配置中心 前置知识 完成ZooKeeper集群搭建以及熟悉ZooKeeperAPI基本使用 需求 很多程序往 ...
- Oracle学习笔记三 SQL命令
SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)
- [Firefly引擎][学习笔记三][已完结]所需模块封装
原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读: 笔记三主要就是各个模块的封装了,这里贴 ...
- JSP学习笔记(三):简单的Tomcat Web服务器
注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...
- java之jvm学习笔记三(Class文件检验器)
java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...
- VSTO学习笔记(三) 开发Office 2010 64位COM加载项
原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...
随机推荐
- python新手如何编写一个猜数字小游戏
此文章只针对新手,希望大家勿喷,感谢!话不多说先上代码: import random if __name__ == '__main__': yourname = input("你好! 你的名 ...
- if-else连用时的陷阱
近日,在实现<The C Programing Language>上的一个练习题时,写出了下面一段代码 ; i<=right; i++) { ) ) swap(v, i, ++la ...
- leetcode--js--Two Sum
问题描述: 给定一个整数数列,找出其中和为特定值的那两个数. 你可以假设每个输入都只会有一种答案,同样的元素不能被重用. 示例: 给定 nums = [2, 7, 11, 15], target = ...
- java开发学生宿舍管理系统源码
开发环境: Windows操作系统开发工具: Eclipse+Jdk+Tomcat+MySQL 运行效果图
- StarUML之五、StarUMl中Formatting Diagram-格式化图
这章比较简单,主要是对视图元素的样式调整 主要是在视图元素右下角设置,可以修改视图元素的相关样式 字体样式 颜色 链接线样式 对齐样式 Stereotype Display-视图元素的样式属性 菜单F ...
- Linux分区工具-parted
parted用于操纵磁盘分区的程序,通常用于规则大小超过2T的分区,也可用于小分区的规划:它支持多种分区表格式,包括MS-DOS(MBR)和GPT:这对于为新操作系统创建空间,重新组织磁盘使用以及将数 ...
- MFC/QT 学习笔记(四)——MFC基于对话框学习控件(上)
新建项目->MFC模板->MFC应用程序->应用程序类型:基于对话框->...OK 解决方案资源管理器->资源文件->xxx.rc->进入:资源视图-> ...
- Centos7 安装Python3.7
如果电脑自带的python2.7 先卸载 1.强制删除已安装python及其关联 rpm -qa|grep python|xargs rpm -ev --allmatches --nodeps 2.删 ...
- RAID | 故障处理
RAID | 故障处理 Unconfigured(good), Spun Up 背景:磁盘替换后在导入外部配置时提示失败,磁盘状态如题. MegaCli -pdgetmissing -a0查看miss ...
- 选择排序 C++实现
实现思想: 1.寻找[i, n)区间里的最小值min ( i>= 0 ) 2.交换min和第i的数 ( i>= 0 ) #include <iostream> #include ...