Unity的C#编程教程_62_语言集成查询 LINQ 详解及应用练习

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,更简洁易用。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值