Unity的C#编程教程_62_语言集成查询 LINQ 详解及应用练习
目录:
LINQ: Querys
1. Any
2. Contains
3. Distinct
4. Where
Challenge: Hands on with LINQ
LINQ: Order by Descending
Challenge: Filter Items with LINQ
LINQ: How to Read and Convert Query Syntax
1. Any
2. Contains
3. Distinct
4. Where
Challenge: Hands on with LINQ
LINQ: Order by Descending
Challenge: Filter Items with LINQ
LINQ: How to Read and Convert Query Syntax
LINQ: Querys
1. Any
-
LINQ: Language Integrated Query 语言集成查询
-
类似 MySQL,允许过滤数据(array 和 list)
-
任务说明:
- 建立一个名字的数组
- 查询某个名字是否在该数组中
之前的做法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LinqTest : MonoBehaviour
{
public string[] names = { "xiaoA", "xiaoB", "xiaoC", "xiaoD" };
// Start is called before the first frame update
void Start()
{
foreach(var name in names)
{
if(name == "xiaoC")
{
Debug.Log("Name found!");
}
}
}
// Update is called once per frame
void Update()
{
}
}
改用 LINQ:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq; // LINQ 需要使用这个库
public class LinqTest : MonoBehaviour
{
public string[] names = { "xiaoA", "xiaoB", "xiaoC", "xiaoD" };
// Start is called before the first frame update
void Start()
{
/*
foreach(var name in names)
{
if(name == "xiaoC")
{
Debug.Log("Name found!");
}
}
*/
var answer = names.Any(name => name == "xiaoE");
// 在 names 数组中,是否有任何满足条件的元素?
// 条件是 name == "xiaoC"
// 返回的是 bool 值
Debug.Log("Fond xiaoE? Answer: " + answer);
}
// Update is called once per frame
void Update()
{
}
}
2. Contains
- 用于判断是否存在具体的元素
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq; // LINQ 需要使用这个库
public class LinqTest : MonoBehaviour
{
public string[] names = { "xiaoA", "xiaoB", "xiaoC", "xiaoD" };
// Start is called before the first frame update
void Start()
{
/*
foreach(var name in names)
{
if(name == "xiaoC")
{
Debug.Log("Name found!");
}
}
*/
/*
var answer = names.Any(name => name == "xiaoE");
// 在 names 数组中,是否有任何元素可以满足特定条件?
// 条件是 name == "xiaoC"
// 返回的是 bool 值
*/
var answer = names.Contains("xiaoE");
Debug.Log("Fond xiaoE? Answer: " + answer);
}
// Update is called once per frame
void Update()
{
}
}
3. Distinct
- 去除重复元素
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq; // LINQ 需要使用这个库
public class LinqTest : MonoBehaviour
{
public string[] names = new string[] { "xiaoA", "xiaoA", "xiaoB", "xiaoC", "xiaoD" };
// Start is called before the first frame update
void Start()
{
Debug.Log("Before");
foreach (string name in names)
{
Debug.Log(name);
}
var newNames = names.Distinct();
// Distinct 不会直接作用于原数组,所以需要赋值到一个新的变量
Debug.Log("New");
foreach (var name in newNames)
{
Debug.Log(name);
}
Debug.Log("After");
foreach (var name in names)
{
Debug.Log(name);
}
}
// Update is called once per frame
void Update()
{
}
}
注意,Distinct 不会直接修改原数组。
4. Where
- 为序列按照指定条件筛选
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq; // LINQ 需要使用这个库
public class LinqTest : MonoBehaviour
{
public string[] names = new string[] { "xiaoAA", "xiaoA", "xiaoBB", "xiaoCCCC", "xiaoDDDD" };
// Start is called before the first frame update
void Start()
{
var newNames = names.Where(name => name.Length > 6);
// 对于原来数组中的元素进行筛选
// 筛选条件是:长度大于 6
foreach(var name in newNames)
{
Debug.Log(name);
}
}
// Update is called once per frame
void Update()
{
}
}
Challenge: Hands on with LINQ
- 任务说明:
- 建立一个数组,包含的都是整型元素,每个元素取值范围 0~100
- 筛选出 50 以上的数据
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq; // LINQ 需要使用这个库
public class LinqTest : MonoBehaviour
{
public int[] nums = { 10, 20, 35, 66, 78, 98, 45, 23, 67 };
// Start is called before the first frame update
void Start()
{
var newNums = nums.Where(num => num > 50);
foreach(var num in newNums)
{
Debug.Log(num);
}
}
// Update is called once per frame
void Update()
{
}
}
LINQ: Order by Descending
- 筛选后进行排序
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq; // LINQ 需要使用这个库
public class LinqTest : MonoBehaviour
{
public int[] nums = { 10, 20, 35, 66, 78, 98, 45, 23, 67 };
// Start is called before the first frame update
void Start()
{
var newNums = nums.Where(num => num > 50).OrderByDescending(n => n);
// 筛选出大于 50 的元素,然后直接按照降序排列
// 排序条件可以定制,比如设定 n => -n,其实就按照升序排列了
foreach (var num in newNums)
{
Debug.Log(num);
}
}
// Update is called once per frame
void Update()
{
}
}
Challenge: Filter Items with LINQ
- 任务说明:
- 创建一个 class,用作筛选
- 筛选对象为游戏道具
- 查询 id 为 3 的物品是否存在,打印查询结果
- 筛选 50 元以上的物品,打印查询结果
- 计算所有道具的平均价格
创建基本脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq; // LINQ 需要使用这个库
[System.Serializable] // 在 inspector 中可见
public class Item
{
public string name;
public int id;
public int price;
}
public class LinqTest : MonoBehaviour
{
public List<Item> items;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
然后在 inspector 中创建一些 item。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq; // LINQ 需要使用这个库
[System.Serializable] // 在 inspector 中可见
public class Item
{
public string name;
public int id;
public int price;
}
public class LinqTest : MonoBehaviour
{
public List<Item> items;
// Start is called before the first frame update
void Start()
{
var result = items.Any(item => item.id == 3);
Debug.Log("Fond id of 3: " + result);
var newItems = items.Where(item => item.price > 50);
foreach(var item in newItems)
{
Debug.Log("Item: " + item.name + " Price: " + item.price);
}
var total = items.Sum(item => item.price); // 求总价
float averagePrice = (float)total / items.Count(); // 平均价
// 为了确保平均价格为浮点数,这里把 total 设置为 float
Debug.Log("Average price: " + averagePrice);
// 也可以直接使用 average:
var average = items.Average(item => item.price);
Debug.Log("Average price: " + average);
}
// Update is called once per frame
void Update()
{
}
}
LINQ: How to Read and Convert Query Syntax
- LINQ 的另一种使用方法:查询语法(query syntax)
微软官方示例:
class LINQQueryExpressions
{
static void Main()
{
// Specify the data source.
int[] scores = new int[] { 97, 92, 81, 60 };
// Define the query expression.
IEnumerable<int> scoreQuery =
from score in scores
where score > 80
select score; // select 语句是必须的
// Execute the query.
foreach (int i in scoreQuery)
{
Console.Write(i + " ");
}
}
}
// Output: 97 92 81
放到 unity 的脚本中:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq; // LINQ 需要使用这个库
public class LinqTest : MonoBehaviour
{
// Specify the data source.
int[] scores = new int[] { 97, 92, 81, 60 };
// Start is called before the first frame update
void Start()
{
// Define the query expression.
IEnumerable<int> scoreQuery =
from score in scores
where score > 80
select score;
// Execute the query.
foreach (int i in scoreQuery)
{
Debug.Log(i + " ");
}
}
// Update is called once per frame
void Update()
{
}
}
这里使用的就是查询语法(query syntax),如何转化为 method syntax 呢:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq; // LINQ 需要使用这个库
public class LinqTest : MonoBehaviour
{
// Specify the data source.
int[] scores = new int[] { 97, 92, 81, 60 };
// Start is called before the first frame update
void Start()
{
// Define the query expression.
/*
IEnumerable<int> scoreQuery =
from score in scores
where score > 80
select score;
*/
var scoreQuery = scores.Where(score => score > 80);
// Execute the query.
foreach (int i in scoreQuery)
{
Debug.Log(i + " ");
}
}
// Update is called once per frame
void Update()
{
}
}
推荐使用 method syntax,更简洁易用。