概述

本篇总结和介绍一下Godot普通数组Array的一些常见用法,包括增、删、查、改和排序、去重、元素计数以及批量操作等。



创建数组

创建普通数组,主要有两种方法,一种是构造函数,一种是方括号指定元素的形式。

var arr = Array(); # 构造函数形式创建空数组
var arr2 = [];     # 方括号形式创建空数组
var arr3 = [1,2,"张三"] # 方括号形式创建非空数组

利用全局range()函数创建数组

var arr = range(10);   # 创建数组
print(arr) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

获取元素

var arr = range(10); # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 下标形式
print(arr[0]) # 0
print(arr[9]) # 9
print(arr[10]) # 下标超出范围,报错

# 方法形式
print(arr.front()) # 0
print(arr.back()) # 9
@tool
extends EditorScript


func _run():
	var arr = [1,2,3];
	print(arr.front()); # 1 # 相当于arr[0]
	print(arr.back());  # 3 # 相当于arr[arr.size()-1]

arr.front()相当于arr[0]arr.back()相当于arr[arr.size()-1]。但两种写法在空数组时都会报错:

@tool
extends EditorScript


func _run():
	var arr = [];
	print(arr[0]);             # 报错
	print(arr[arr.size()-1]);  # 报错
@tool
extends EditorScript


func _run():
	var arr = [];
	print(arr.front()); # 报错
	print(arr.back());  # 报错

添加元素

@tool
extends EditorScript


func _run():
	var arr = [1,2,4]; # 原始数组
	
	arr.push_front(0);              # 在数组起始(下标0)位置添加新元素
	print(arr); # [0, 1, 2, 4]
	arr.push_back(5);               # 在数组末尾(下标size()-1)位置添加新元素
	print(arr); # [0, 1, 2, 4, 5]
	arr.append(6)                   # 在数组末尾(下标size()-1)位置添加新元素
	print(arr); # [0, 1, 2, 4, 5, 6]
	arr.append_array([7,8,9]);      # 在末尾追加数组
	print(arr); # [0, 1, 2, 4, 5, 6, 7, 8, 9]
	arr += [10,11,12];              # 在末尾追加数组
	print(arr); # [0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12]
	arr.insert(3,3);                # 在指定下标位置添加新元素
	print(arr); # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

删除元素

@tool
extends EditorScript


func _run():
	var arr = [1,2,3,4,5,6]; # 原始数组
	
	arr.remove_at(0); # 移除指定下标位置的元素,不返回任何值
	print(arr); # [2, 3, 4, 5, 6]
	arr.pop_at(0);    # 移除指定下标位置的元素,并返回该元素
	print(arr); # [3, 4, 5, 6]
	arr.pop_front()   # 移除并返回数组的第一个元素。等效于pop_at(0)
	print(arr); # [4, 5, 6]
	arr.pop_back()    # 移除并返回数组中的末尾元素。等效于pop_at(size()-1)
	print(arr); # [4, 5]
	arr.erase(4)      # 移除数组中第一个匹配的值
	print(arr); # [5]
	arr.clear()       # 清空数组
	print(arr); # []  # 清空数组,等价于arr.resize(0)
	print(arr.is_empty()); # true 

批量处理

all()判断所有元素是否都符合某一条件

@tool
extends EditorScript


func _run():
	var arr = [1,2,3];
	# 判断数组中的元素是不是全大于5
	var result = arr.all(func(num):
		return num > 5;
	)
	print(result) # false

any()判断所有元素是否至少有一个满足条件

@tool
extends EditorScript


func _run():
	var arr = [1,2,3];
	# 判断数组中有没有大于5的数
	var result = arr.any(func(num):
		return num > 5;
	)
	print(result) # false
@tool
extends EditorScript


func _run():
	var arr = [1,2,3,10,34,56];
	# 判断数组中有没有大于5的数
	var result = arr.any(func(num):
		return num > 5;
	)
	print(result) # true

filter()过滤出满足某一条件的所有元素

@tool
extends EditorScript


func _run():
	var arr = [1,2,3,10,34,56];
	# 判断数组中的元素是不是全大于5
	var result = arr.filter(func(num):
		return num > 5;
	)
	print(result) # [10, 34, 56]

map()对所有元素进行统一的处理

所有元素+5
@tool
extends EditorScript


func _run():
	var arr = [1,2,3,10,34,56];
	# 对所有元素进行处理,然后返回新数组
	var result = arr.map(func(num):
		return num + 5;
	)
	print(result) # [6, 7, 8, 15, 39, 61]
所有元素变为原来的2倍
@tool
extends EditorScript


func _run():
	var arr = [1,2,3,10,34,56];
	# 对所有元素进行处理,然后返回新数组
	var result = arr.map(func(num):
		return num * 2;
	)
	print(result) # [2, 4, 6, 20, 68, 112]

将所有元素变为字符串类型
@tool
extends EditorScript


func _run():
	var arr = [1,2,3,10,34,56];
	# 
	var result = arr.map(func(num):
		return str(num);
	)
	print(result) # ["1", "2", "3", "10", "34", "56"]

reduce()累计结果

数组元素求和

@tool
extends EditorScript


func _run():
	var arr = [1,2,3,4,5,6];
	# 对数组元素累加,其中a可以指定一个基数,结果将累加在这个基数上,不指定则默认为第一个元素的值
	var result = arr.reduce(func(a,num):
		return a + num;
	)
	print(result) # 21
func _run():
	var arr = [1,2,3,4,5,6];
	# 数组元素累加
	var result = arr.reduce(func(a,num):
		return a + num;
	,30) # 指定a为30,则整个结果变为 30 + 1 + 2 + 3 + 4 + 5 + 6
	print(result) # 51

数组元素求积

@tool
extends EditorScript


func _run():
	var arr = [1,2,3,4,5,6];
	# 数组元素累乘
	var result = arr.reduce(func(a,num):
		return a * num;
	)
	print(result) # 720

字符串连接的reduce实现形式

@tool
extends EditorScript


func _run():
	var arr = ["张三","李四","王五"];
	# 
	var result = arr.reduce(func(a,item):
		return "%s,%s" % [a,item];
	)
	print(result) # 张三,李四,王五
@tool
extends EditorScript


func _run():
	var arr = ["张三","李四","王五"];
	# 
	var result = arr.reduce(func(a,item):
		return "%s,%s" % [a,item];
	,"二麻子")
	print(result) # 二麻子,张三,李四,王五

count()获取元素出现的次数

@tool
extends EditorScript


func _run():
	var arr = ["张三","李四","王五","二麻子","李四",];
	print(arr.count("李四")) # 2

fill()填充或初始化所有数组元素

@tool
extends EditorScript


func _run():
	var arr = [];   # 创建空数组
	arr.resize(10); # 重新设定数组大小
	arr.fill(0);    # 数组的所有元素填充为0
	
	print(arr) # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

如果是非空数组,被fill()后原来的元素会被全部修改为填充的元素。

@tool
extends EditorScript


func _run():
	var arr = [12,34,56];   # 创建数组
	arr.fill(0);    # 数组的所有元素修改为0
	
	print(arr) # [0, 0, 0]

默认,如果创建空数组后,只resize()不填充,则所有元素为null

var arr = [];   # 创建数组
arr.resize(4);  # 重新设定数组大小
print(arr)      # [<null>, <null>, <null>, <null>]

不要只拘泥于数字,数组中的元素可以是任意的简单类型、符合类型以及对象。

@tool
extends EditorScript


func _run():
	var arr = [];   # 创建数组
	arr.resize(4);  # 重新设定数组大小
	arr.fill(Vector2.ZERO);    # 初始化为0向量
	
	print(arr) # [(0, 0), (0, 0), (0, 0), (0, 0)]

查找

find() & rfind()

find()返回找到的第一个相同元素的位置,找不到返回-1。
rfind()从末尾开始逆序查找,返回找到的第一个相同元素的位置(索引),找不到返回-1。

@tool
extends EditorScript


func _run():
	var arr = [0, 1, 2, 3, 4, 5, 6, 4, 8, 9]; 
	print(arr.find(4))  # 4 -- 从左往右 - 正序查找,返回查找到的[第一个]元素的 - 正序索引
	print(arr.rfind(7)) # 7 -- 从右往左 - 逆序查找,返回查找到的[第一个]元素的 - 正序索引

两者都可以定义第二个参数,决定从哪个位置开始。

has()判断数组中是否存在某元素

@tool
extends EditorScript


func _run():
	var arr = [0, 1, 2, 3, 4, 5, 6, 4, 8, 9];
	print(arr.has(9));  # true
	print(arr.has(10)); # false

等效写法为元素 in 数组:

@tool
extends EditorScript


func _run():
	var arr = [0, 1, 2, 3, 4, 5, 6, 4, 8, 9];
	print(9 in arr);  # true
	print(10 in arr); # false

只读

@tool
extends EditorScript


func _run():
	var arr = [1,2,3,4,5,6]; # 原始数组
	arr.make_read_only()
	print(arr.is_read_only()) # true
	arr.append(7) # 报错:Array is in read-only state.

求最大、最小

@tool
extends EditorScript


func _run():
	var arr = [1,2,3,4,5,6]; # 原始数组
	print(arr.min()) # 1
	print(arr.max()) # 6
@tool
extends EditorScript


func _run():
	var arr = [Vector2(0,0),Vector2(40,10),Vector2(100,100)]; # 原始数组
	print(arr.min()) # (0,0)
	print(arr.max()) # (100,100)

随机

pick_random()从数组中随机选取一个元素

@tool
extends EditorScript


func _run():
	var arr = [2,6,9]; # 原始数组
	print(arr.pick_random()) # 从数组的3个元素中随机选取一个返回

shuffle()打乱元素顺序

@tool
extends EditorScript


func _run():
	var arr = [2,6,9]; # 原始数组
	arr.shuffle()      # 打乱原来数组元素的顺序
	print(arr)         # 每次结果不一样

排序

reverse() 将数组中的元素逆序排列

@tool
extends EditorScript


func _run():
	var arr = range(10); # 原始数组
	print(arr) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
	arr.reverse() # 将数组中的元素逆序排列。
	print(arr) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

sort()升序,sort()+reverse()降序

@tool
extends EditorScript


func _run():
	var arr = range(10); # 原始数组
	arr.shuffle() # 打乱顺序
	print(arr)    # [9, 7, 3, 1, 4, 2, 8, 6, 0, 5]
	arr.sort()    # 将数组中的元素升序排列
	print(arr)    # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
	arr.reverse() # 升序+逆序=降序
	print(arr)    # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

sort_custom()自定义函数进行排序

@tool
extends EditorScript


func _run():
	var arr = ["百度","阿里巴巴","美团","支付宝"]; # 原始数组
	arr.shuffle() # 打乱顺序
	print(arr)    # ["阿里巴巴", "百度", "支付宝", "美团"]
	# 将数组中的元素按字符串长度降序排列
	arr.sort_custom(func(a:String,b:String):
		return true if a.length() > b.length() else false
	)    
	print(arr)    # ["阿里巴巴", "支付宝", "百度", "美团"]
@tool
extends EditorScript


func _run():
	var arr = ["百度","阿里巴巴","美团","支付宝"]; # 原始数组
	arr.shuffle() # 打乱顺序
	print(arr)    # ["支付宝", "阿里巴巴", "百度", "美团"]
	# 将数组中的元素按字符串长度升序排列
	arr.sort_custom(func(a:String,b:String):
		return true if a.length() < b.length() else false
	)    
	print(arr)    # ["百度", "美团", "支付宝", "阿里巴巴"]

assign()覆盖

@tool
extends EditorScript


func _run():
	var arr1 = ["百度","阿里巴巴","美团","支付宝"]; # 数组1
	var arr2 = [1,2,3,4] # 数组2
	arr1.assign(arr2); # 用数组2覆盖数组1
	print(arr1) # [1,2,3,4]
	print(arr2) # [1,2,3,4]

duplicate()创建副本

@tool
extends EditorScript


func _run():
	var arr1 = ["百度","阿里巴巴","美团","支付宝"]; # 数组1
	var arr2 = arr1.duplicate() # 创建数组1的副本
	print(arr1) # ["百度", "阿里巴巴", "美团", "支付宝"]
	print(arr2) # ["百度", "阿里巴巴", "美团", "支付宝"]

hash()求数组哈希值

@tool
extends EditorScript


func _run():
	var arr = [0, 1, 2, 3, 4, 5, 6, 4, 8, 9]; 
	print(arr.hash())  # 1797923815

:::success
内容相同的 Array 会得到一致的哈希值。然而,反之不然。返回一致的哈希值并不意味着数组相等,因为不同的数组可能因为哈希碰撞而得到一致的哈希值。
:::
判断两个数组是否完全相等,可以使用==!=运算符。

@tool
extends EditorScript


func _run():
	var arr1 = [0, 1, 2, 3, 4, 5, 6, 4, 8, 9];
	var arr2 = [0, 1, 2, 3, 4, 5, 6, 4, 8, 9];
	print(arr1 == arr2)  # true

类型化数组与类型判断以及类型转换

Packed*Array与普通Array之间可以通过构造函数转化。

@tool
extends EditorScript


func _run():
	var arr = PackedStringArray([1,2,4]); # ArrayPackedStringArray
	print(arr) # ["1", "2", "4"]

与字符串的转化

@tool
extends EditorScript


func _run():
	var arr_str = "张三,李四,王五"; # 原始字符串
	var arr = arr_str.split(",")
	print(arr) # ["张三", "李四", "王五"]
@tool
extends EditorScript


func _run():
	var arr = ["张三", "李四", "王五"]; # 原始数组
	var arr_str = ",".join(arr);
	print(arr_str) # "张三,李四,王五"

数组切分

var arr = ["张三","李四","王五","二麻子"]
arr.slice(0,2) # 等价于 

去重

算法1

  • 创建一个空数组arr2,通过不断的遍历需要去重的数组arr,判断每个元素是否已经在arr2中:
  • 如果存在,直接从arr中删除该元素
  • 如果不存在,则将该元素添加到arr2,并从arr中删除
  • 不断循环,直到arr为空
# 数组去重 - 算法1
func norepeat(arr:Array) -> Array:
	arr = arr.duplicate(true) # 使用副本而不是对原数组进行操作
	var arr2 = []
	while !arr.is_empty():
		for item in arr:
			if item not in arr2:
				arr2.append(item)
				arr.erase(item)
			else:
				arr.erase(item)
	return arr2
@tool
extends EditorScript

func _run():
	var arr = [1,2,3,4,5,4,5,4,5,6,7]; # 原始数组
	print(norepeat(arr)) # [1, 3, 5, 7, 2, 4, 6]

算法2

  • 构造一个空字典dict
  • 遍历需要去重的数组arr中的元素item,以dict[item] = item形式添加键值对,添加的过程本身就是在去重
  • 通过dict.keys()dict.values()就可以获得去重的数组
# 数组去重 - 算法2
func norepeat2(arr:Array) -> Array:
	arr = arr.duplicate(true) # 使用副本而不是对原数组进行操作
	var dict:Dictionary = {}
	for item in arr:
		dict[item] = item
	return dict.keys() # dict.values()也可以
func _run():
	var arr = [1,2,3,4,5,4,5,4,5,6,7]; # 原始数组
	print(norepeat2(arr)) # [1, 2, 3, 4, 5, 6, 7]
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐