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,更簡潔易用。