App Inventor 2 字典(Dictionary)操作教程 - 键值对数据结构

« 返回首页

什么是字典(Dictionary)

字典(Dictionary)是一种键值对(Key-Value Pair)数据结构,它通过唯一的”键”来关联对应的”值”。在其他编程语言中,字典也被称为映射(Map)、关联数组(Associative Array)或哈希表(HashMap)。

打个比方:字典就像一本电话簿,”姓名”是键,”电话号码”是值。你不需要记住电话号码在第几页(不需要索引),只需通过姓名就能找到对应的号码。

字典 vs 列表

特性 列表(List) 字典(Dictionary)
访问方式 通过索引(数字位置) 通过键(文本或其他类型)
顺序 有序 无序
适用场景 有序数据集合 需要通过名称快速查找数据
示例 ["苹果", "香蕉", "橙子"] {"name": "小明", "age": 12}
查找效率 需遍历 直接通过键查找,效率高

JSON与字典的关系

JSON(JavaScript Object Notation)中的对象{})在App Inventor中就是字典,JSON中的数组[])对应列表

{
  "id": 1,
  "name": "Tim the Beaver",
  "school": {
    "name": "Massachusetts Institute of Technology"
  },
  "enrolled": true,
  "classes": ["6.001", "18.01", "8.01"]
}

上面的JSON数据中,键可以是文本、数字、布尔值,值可以是任何类型(文本、数字、布尔值、字典、列表)。

字典积木块概览

App Inventor 2 中的字典积木块位于「内置块 → 字典」类别中,共提供以下积木块:

积木块 功能
create empty dictionary 创建空字典
make a dictionary 用键值对创建字典
pair 构造键值对
get value for key 根据键获取值
set value for key 设置/添加键值对
delete entry for key 删除键值对
get value at key path 沿路径获取嵌套值
set value for key path 沿路径设置嵌套值
get keys 获取所有键的列表
get values 获取所有值的列表
is key in dictionary? 判断键是否存在
size of dictionary 获取键值对数量
list of pairs to dictionary 关联列表转字典
dictionary to list of pairs 字典转关联列表
copy dictionary 深拷贝字典
merge into dictionary 合并字典
list by walking key path 沿路径收集值列表
walk all at level 遍历当前层所有元素
is a dictionary? 判断是否为字典

创建字典

方法一:create empty dictionary(创建空字典)

创建一个没有任何键值对的空字典,后续可通过 set value for key 添加数据。

设 变量 myDict 为 create empty dictionary
// myDict = {}(空字典)

使用场景: 当字典的内容需要在程序运行过程中动态添加时,先创建一个空字典。

方法二:make a dictionary + pair(直接创建含数据的字典)

如果预先知道字典的内容,可以用 make a dictionary 结合 pair 积木块直接创建:

设 变量 student 为 make a dictionary
  pair("name", "小明")
  pair("age", 12)
  pair("grade", "六年级")
// student = {"name": "小明", "age": 12, "grade": "六年级"}

说明: pair 积木块专门用于构造键值对,只能在 make a dictionary 内部使用。点击 make a dictionary 积木块上的蓝色齿轮图标,可以添加更多的 pair 条目。

提示: create empty dictionary 积木块也可以通过点击蓝色齿轮按钮添加 pair 条目,将其变为 make a dictionary 积木块。

添加和修改键值对

set value for key(设置键值对)

这是向字典中添加新键值对修改已有键值对的核心积木块。

// 添加新的键值对
set value for key "name" in dictionary myDict to "小红"

// 添加更多键值对
set value for key "age" in dictionary myDict to 13
set value for key "score" in dictionary myDict to 95.5

// myDict = {"name": "小红", "age": 13, "score": 95.5}

行为说明:

  • 如果字典中不存在该键,则新建一个键值对
  • 如果字典中已存在该键,则替换原来的值
// 修改已有键值对
set value for key "name" in dictionary myDict to "小刚"
// myDict = {"name": "小刚", "age": 13, "score": 95.5}

从2个键值对增加到3个或更多

用户经常问:”字典里已经有2个键值对,如何增加到3个?”答案是使用 set value for key 动态添加:

// 假设已有字典: {"name": "小明", "age": 12}
// 要增加第3个键值对:
set value for key "grade" in dictionary student to "六年级"
// 现在 student = {"name": "小明", "age": 12, "grade": "六年级"}

// 继续增加更多:
set value for key "school" in dictionary student to "实验小学"
set value for key "hobby" in dictionary student to "编程"

核心要点: 字典的键值对数量没有上限,随时可以通过 set value for key 添加新的键值对。

获取值

get value for key(根据键获取值)

通过键名获取字典中对应的值:

设 变量 name 为 get value for key "name" from dictionary myDict
// 如果 myDict = {"name": "小明", "age": 12},则 name = "小明"

// 如果键不存在,返回 "not found" 参数的默认值
设 变量 email 为 get value for key "email" from dictionary myDict
  not found: "无邮箱"
// email = "无邮箱"(因为字典中没有 "email" 键)

行为说明: 如果字典中存在该键,返回对应的值;如果不存在,返回 not found 参数指定的默认值。

get value at key path(沿路径获取嵌套值)

对于多层嵌套的数据结构,可以使用 get value at key path 通过路径一次性获取深层值。

// 假设有嵌套字典:
// student = {
//   "name": "小明",
//   "school": {
//     "name": "实验小学",
//     "city": "北京"
//   }
// }

// 获取学校名称 - 逐层获取:
设 变量 schoolName 为 get value at key path
  path: make a list("school", "name")
  from dictionary: student
// schoolName = "实验小学"

路径中可以混合使用键名和数字索引:

// 假设有混合数据:
// data = {
//   "name": "Tim",
//   "classes": ["6.001", "18.01", "8.01"]
// }

// 获取第二门课程(索引从1开始)
设 变量 secondClass 为 get value at key path
  path: make a list("classes", 2)
  from dictionary: data
// secondClass = "18.01"

说明: get value for key 等价于 get value at key path 的路径长度为1的情况。当路径中遇到字典时使用键名,遇到列表时使用数字索引。

set value for key path(沿路径设置嵌套值)

get value at key path 互为镜像操作,用于更新嵌套结构中的值:

// 修改嵌套字典中的学校名称
set value for key path
  path: make a list("school", "name")
  in dictionary: student
  to value: "第一中学"

行为说明:

  • 路径必须有效,但最后一个键可以不存在
  • 如果最后一个键不存在,会创建新的键值对
  • 如果最后一个键已存在,会替换原来的值

删除键值对

delete entry for key(删除指定键的条目)

// 假设 myDict = {"name": "小明", "age": 12, "grade": "六年级"}
delete entry for key "age" from dictionary myDict
// myDict = {"name": "小明", "grade": "六年级"}

// 如果键不存在,字典不受影响
delete entry for key "email" from dictionary myDict
// myDict 不变

行为说明: 删除字典中指定键对应的键值对。如果键不存在,字典不做任何修改。

遍历字典

获取所有键:get keys

设 变量 allKeys 为 get keys from dictionary myDict
// 如果 myDict = {"name": "小明", "age": 12},则 allKeys = ["name", "age"]

获取所有值:get values

设 变量 allValues 为 get values from dictionary myDict
// 如果 myDict = {"name": "小明", "age": 12},则 allValues = ["小明", 12]

注意: get values 返回的列表中的值与字典中的值是引用关系。修改列表中的值(如果值本身是字典或列表),也会同步修改字典中的值。

使用 for each 循环遍历字典

通过 get keys 获取所有键,再用循环遍历:

设 变量 myDict 为 make a dictionary
  pair("语文", 92)
  pair("数学", 88)
  pair("英语", 95)

设 变量 keys 为 get keys from dictionary myDict
for each item key in list keys do:
  设 变量 value 为 get value for key key from dictionary myDict
  设置 Label1.文本 为 join(Label1.文本, "\n", key, ": ", value)
// 输出:
// 语文: 92
// 数学: 88
// 英语: 95

判断键是否存在:is key in dictionary?

如果 is key in dictionary? key: "email" in dictionary myDict 则
  设置 Label1.文本 为 get value for key "email" from dictionary myDict
否则
  设置 Label1.文本 为 "未设置邮箱"

获取键值对数量:size of dictionary

设 变量 count 为 size of dictionary myDict
// 如果 myDict = {"name": "小明", "age": 12},则 count = 2

嵌套字典

字典的值可以是另一个字典,形成多层嵌套结构。这在处理复杂JSON数据时非常常见。

设 变量 student 为 make a dictionary
  pair("name", "小明")
  pair("contact", make a dictionary
    pair("phone", "13800138000")
    pair("email", "xiaoming@example.com")
  )
  pair("address", make a dictionary
    pair("city", "北京")
    pair("district", "海淀区")
    pair("street", "中关村大街1号")
  )

访问嵌套字典中的值有两种方式:

方式一:逐层获取

设 变量 contact 为 get value for key "contact" from dictionary student
设 变量 phone 为 get value for key "phone" from dictionary contact
// phone = "13800138000"

方式二:使用 key path 一次性获取

设 变量 phone 为 get value at key path
  path: make a list("contact", "phone")
  from dictionary: student
// phone = "13800138000"

推荐使用方式二,代码更简洁高效。

字典与列表转换

list of pairs to dictionary(关联列表转字典)

将形如 ((key1 value1) (key2 value2) ...) 的关联列表转换为字典:

设 变量 pairList 为 make a list
  make a list("name", "小明")
  make a list("age", 12)
  make a list("grade", "六年级")

设 变量 myDict 为 list of pairs to dictionary pairList
// myDict = {"name": "小明", "age": 12, "grade": "六年级"}

为什么要转换? 字典的查找效率比关联列表高。如果你需要对一个关联列表进行大量查找操作,建议先转换为字典。

dictionary to list of pairs(字典转关联列表)

将字典转换为关联列表,这是 list of pairs to dictionary 的逆操作:

设 变量 myDict 为 make a dictionary
  pair("name", "小明")
  pair("age", 12)

设 变量 pairList 为 dictionary to list of pairs myDict
// pairList = (("name" "小明") ("age" 12))

这两个操作互为逆操作,可以互相转换:

设 变量 original 为 make a dictionary pair("a", 1) pair("b", 2)
设 变量 pairs 为 dictionary to list of pairs original
设 变量 restored 为 list of pairs to dictionary pairs
// restored 和 original 内容相同

复制和合并字典

copy dictionary(深拷贝字典)

设 变量 original 为 make a dictionary
  pair("name", "小明")
  pair("scores", make a list(90, 85, 92))

设 变量 copied 为 copy dictionary original

// 修改副本不会影响原字典
set value for key "name" in dictionary copied to "小红"
// original.name 仍然是 "小明"
// copied.name 变为 "小红"

重要: copy dictionary 执行的是深拷贝(deep copy),即所有值都会被递归复制。修改副本中的任何值(包括嵌套的字典或列表)都不会影响原字典。

merge into dictionary(合并字典)

将一个字典的键值对复制到另一个字典中:

设 变量 defaults 为 make a dictionary
  pair("theme", "light")
  pair("language", "zh")
  pair("fontSize", 14)

设 变量 userPrefs 为 make a dictionary
  pair("language", "en")
  pair("fontSize", 16)

merge into dictionary from dictionary userPrefs into dictionary defaults
// defaults = {"theme": "light", "language": "en", "fontSize": 16}
// 注意:"language" 和 "fontSize" 被用户设置覆盖了

行为说明: 如果源字典和目标字典有相同的键,目标字典中的值会被源字典的值覆盖

高级遍历:walk key path

list by walking key path(沿路径收集值)

这是最强大的字典操作积木块之一,用于从复杂嵌套结构中批量提取数据。它的工作原理类似 get value at key path,但返回的是一个值列表而不是单个值。

路径中可以包含三种类型的元素:

  1. 字典键 — 沿指定键路径前进
  2. 数字索引 — 沿列表指定位置前进
  3. walk all at level — 遍历当前层的所有元素

示例:从嵌套数据中提取所有人的名字

假设有以下JSON数据:

{
  "people": [
    {"first_name": "Tim", "last_name": "Beaver"},
    {"first_name": "John", "last_name": "Smith"},
    {"first_name": "Jane", "last_name": "Doe"}
  ]
}

获取所有人的 first_name

设 变量 data 为 {上述JSON解析后的字典}

设 变量 firstNames 为 list by walking key path
  from dictionary: data
  path: make a list("people", walk all at level, "first_name")
// firstNames = ["Tim", "John", "Jane"]

路径解析过程:

  1. "people" — 进入 people 键对应的列表
  2. walk all at level — 遍历列表中的每一个元素(每个人)
  3. "first_name" — 获取每个人的 first_name

walk all at level(遍历当前层)

walk all at level 只能在 list by walking key path 的路径中使用,表示遍历当前位置的所有元素:

  • 如果当前位置是字典,遍历字典中所有的值
  • 如果当前位置是列表,遍历列表中所有的元素

复杂示例:提取所有课程名称

{
  "departments": [
    {
      "name": "计算机系",
      "courses": [
        {"title": "Python入门", "credits": 3},
        {"title": "数据结构", "credits": 4}
      ]
    },
    {
      "name": "数学系",
      "courses": [
        {"title": "微积分", "credits": 4},
        {"title": "线性代数", "credits": 3}
      ]
    }
  ]
}
设 变量 allTitles 为 list by walking key path
  from dictionary: data
  path: make a list("departments", walk all at level, "courses", walk all at level, "title")
// allTitles = ["Python入门", "数据结构", "微积分", "线性代数"]

判断数据类型:is a dictionary?

如果 is a dictionary? myData 则
  设置 Label1.文本 为 "这是一个字典,包含 " & (size of dictionary myData) & " 个键值对"
否则 如果 is a list? myData 则
  设置 Label1.文本 为 "这是一个列表,包含 " & (length of list myData) & " 个元素"
否则
  设置 Label1.文本 为 "这是一个普通值"

使用场景: 当从Web API获取数据后,不确定返回的是字典还是列表时,可以用 is a dictionary? 进行判断。

字典在JSON解析中的应用

字典是App Inventor中处理JSON数据的核心工具。JSON解析后的对象会自动转换为字典。

解析JSON字符串

当 Web1.GotText 执行时:
  设 变量 responseCode 为 responseCode
  设 变量 responseContent 为 responseContent
  
  如果 responseCode = 200 则
    // 将JSON文本解析为字典
    设 变量 data 为 call Web1.JsonTextDecodeWithDictionaries(responseContent)
    
    // 从字典中提取数据
    设 变量 name 为 get value for key "name" from dictionary data
    设置 Label1.文本 为 name

解析嵌套JSON

// JSON: {"user": {"profile": {"avatar": "https://..."}}}
设 变量 avatar 为 get value at key path
  path: make a list("user", "profile", "avatar")
  from dictionary: data

解析JSON数组中的对象

// JSON: {"results": [{"name": "A"}, {"name": "B"}]}
设 变量 results 为 get value for key "results" from dictionary data

for each item item in list results do:
  设 变量 name 为 get value for key "name" from dictionary item
  设置 ListPicker1.元素 为 join(ListPicker1.元素, name, ",")

实战案例一:学生成绩管理

使用字典管理多名学生的成绩数据。

数据结构设计

设 全局变量 students 为 create empty dictionary

// 每个学生的数据用嵌套字典表示:
// {
//   "stu001": {"name": "小明", "math": 92, "chinese": 88, "english": 95},
//   "stu002": {"name": "小红", "math": 98, "chinese": 91, "english": 87},
//   "stu003": {"name": "小刚", "math": 85, "chinese": 93, "english": 90}
// }

添加学生

// 添加一个新学生
设 变量 newStudent 为 make a dictionary
  pair("name", "小明")
  pair("math", 92)
  pair("chinese", 88)
  pair("english", 95)

set value for key "stu001" in dictionary students to newStudent

查询学生成绩

设 变量 stuId 为 TextBox1.文本  // 用户输入学号,如 "stu001"

如果 is key in dictionary? key: stuId in dictionary students 则
  设 变量 student 为 get value for key stuId from dictionary students
  设 变量 name 为 get value for key "name" from dictionary student
  设 变量 math 为 get value for key "math" from dictionary student
  设 变量 chinese 为 get value for key "chinese" from dictionary student
  设 变量 english 为 get value for key "english" from dictionary student
  设 变量 total 为 math + chinese + english
  设 变量 average 为 total / 3
  
  设置 Label1.文本 为 join("姓名: ", name, "\n",
    "数学: ", math, "\n",
    "语文: ", chinese, "\n",
    "英语: ", english, "\n",
    "总分: ", total, "\n",
    "平均分: ", format as decimal(average, 1))
否则
  设置 Label1.文本 为 "未找到该学号的学生"

修改学生成绩

设 变量 stuId 为 "stu001"
设 变量 student 为 get value for key stuId from dictionary students
set value for key "math" in dictionary student to 95
// 由于 student 是字典中的引用,修改会直接生效

删除学生

delete entry for key "stu001" from dictionary students

显示所有学生名单

设 变量 ids 为 get keys from dictionary students
设 变量 result 为 ""

for each item id in list ids do:
  设 变量 student 为 get value for key id from dictionary students
  设 变量 name 为 get value for key "name" from dictionary student
  设 变量 result 为 join(result, id, " - ", name, "\n")

设置 Label1.文本 为 result

实战案例二:购物车数据结构

使用字典+列表的组合构建购物车功能。

数据结构设计

// 购物车字典:
// {
//   "items": [
//     {"id": "p001", "name": "苹果", "price": 5.5, "quantity": 3},
//     {"id": "p002", "name": "牛奶", "price": 12.0, "quantity": 2}
//   ],
//   "totalPrice": 40.5,
//   "totalCount": 5
// }

设 全局变量 cart 为 make a dictionary
  pair("items", create empty list)
  pair("totalPrice", 0)
  pair("totalCount", 0)

添加商品到购物车

设 变量 productId 为 "p001"
设 变量 productName 为 "苹果"
设 变量 productPrice 为 5.5

// 检查购物车中是否已有该商品
设 变量 items 为 get value for key "items" from dictionary cart
设 变量 found 为 false
设 变量 foundIndex 为 0

for each item item in list items do:
  设 变量 id 为 get value for key "id" from dictionary item
  如果 id = productId 则
    设 变量 found 为 true
    
如果 found 则
  // 商品已在购物车中,数量+1
  // (需要找到该商品并更新数量)
  for each item item in list items do:
    设 变量 id 为 get value for key "id" from dictionary item
    如果 id = productId 则
      设 变量 qty 为 get value for key "quantity" from dictionary item
      set value for key "quantity" in dictionary item to qty + 1
否则
  // 新商品,添加到购物车
  设 变量 newItem 为 make a dictionary
    pair("id", productId)
    pair("name", productName)
    pair("price", productPrice)
    pair("quantity", 1)
  add items to list
    list: get value for key "items" from dictionary cart
    item: newItem

// 更新总价和总数量
call 更新购物车统计

更新购物车统计

过程 更新购物车统计:
  设 变量 items 为 get value for key "items" from dictionary cart
  设 变量 totalPrice 为 0
  设 变量 totalCount 为 0
  
  for each item item in list items do:
    设 变量 price 为 get value for key "price" from dictionary item
    设 变量 qty 为 get value for key "quantity" from dictionary item
    设 变量 totalPrice 为 totalPrice + price * qty
    设 变量 totalCount 为 totalCount + qty
  
  set value for key "totalPrice" in dictionary cart to totalPrice
  set value for key "totalCount" in dictionary cart to totalCount
  
  设置 TotalLabel.文本 为 join("合计: ¥", format as decimal(totalPrice, 2))
  设置 CountLabel.文本 为 join("共 ", totalCount, " 件商品")

从购物车移除商品

设 变量 items 为 get value for key "items" from dictionary cart
设 变量 newItems 为 create empty list

for each item item in list items do:
  设 变量 id 为 get value for key "id" from dictionary item
  如果 id ≠ 要删除的商品ID 则
    add items to list
      list: newItems
      item: item

set value for key "items" in dictionary cart to newItems
call 更新购物车统计

显示购物车内容

设 变量 items 为 get value for key "items" from dictionary cart
设 变量 display 为 ""

for each item item in list items do:
  设 变量 name 为 get value for key "name" from dictionary item
  设 变量 price 为 get value for key "price" from dictionary item
  设 变量 qty 为 get value for key "quantity" from dictionary item
  设 变量 subtotal 为 price * qty
  设 变量 display 为 join(display, name, 
    " x", qty, 
    "  ¥", format as decimal(subtotal, 2), 
    "\n")

设置 CartLabel.文本 为 display
call 更新购物车统计

字典操作速查表

操作 积木块 说明
创建空字典 create empty dictionary 后续动态添加键值对
创建有数据的字典 make a dictionary + pair 初始化时已知键值对
添加/修改键值对 set value for key 键不存在则新建,存在则替换
获取值 get value for key 键不存在返回默认值
获取嵌套值 get value at key path 支持多层路径和数字索引
设置嵌套值 set value for key path 路径需有效,最后键可不存在
删除键值对 delete entry for key 键不存在则无操作
获取所有键 get keys 返回键的列表
获取所有值 get values 返回值的列表(引用)
判断键是否存在 is key in dictionary? 返回 true/false
获取大小 size of dictionary 返回键值对数量
列表转字典 list of pairs to dictionary 提升查找效率
字典转列表 dictionary to list of pairs 互转操作
深拷贝 copy dictionary 修改副本不影响原字典
合并 merge into dictionary 源字典覆盖目标字典同键
批量提取 list by walking key path 支持路径 + walk all
遍历所有 walk all at level 配合 walking key path
类型判断 is a dictionary? 区分字典和列表

常见问题

1. 字典和列表怎么选择?

  • 需要通过名称查找数据 → 用字典
  • 数据有固定顺序 → 用列表
  • 需要判断某个标识是否存在 → 用字典
  • 需要按序号逐一处理 → 用列表

2. 键可以是数字吗?

可以。字典的键不限于文本,也可以是数字。但在 get value at key path 的路径中,数字会被解释为列表索引。如果需要用数字作为字典的键,建议使用 get value for key 而非 get value at key path

3. 字典中同一个键可以有多个值吗?

不可以。字典中每个键只能对应一个值。如果需要存储多个值,可以将值设为一个列表:

设 变量 student 为 make a dictionary
  pair("name", "小明")
  pair("courses", make a list("数学", "语文", "英语"))

4. get values 返回的列表修改后会影响字典吗?

是的。get values 返回的是字典中值的引用。如果值本身是字典或列表,通过返回列表修改它,字典中的数据也会同步改变。如果不希望互相影响,请使用 copy dictionary 创建副本。

5. 如何调试字典内容?

// 方法一:转为文本查看
设置 DebugLabel.文本 为 join("键: ", get keys from dictionary myDict)
设置 DebugLabel.文本 为 join("值: ", get values from dictionary myDict)

// 方法二:查看大小
设置 DebugLabel.文本 为 join("键值对数量: ", size of dictionary myDict)

// 方法三:检查类型
如果 is a dictionary? myData 则
  设置 DebugLabel.文本 为 "这是一个字典"
否则 如果 is a list? myData 则
  设置 DebugLabel.文本 为 "这是一个列表"

总结

字典是App Inventor 2中处理结构化数据的核心工具,特别适合以下场景:

  1. JSON数据解析 — API返回的JSON对象就是字典
  2. 配置信息存储 — 用键名快速查找配置项
  3. 数据映射关系 — 通过唯一标识关联详细信息
  4. 复杂嵌套数据 — 字典和列表的组合处理多层结构

掌握字典的创建、增删改查、遍历和嵌套操作,是使用App Inventor 2进行高级开发的基础能力。


本文参考了 MIT App Inventor官方文档 - Dictionary Blocks 编写。


© 2025 AppInventor2中文网. 本教程基于 MIT App Inventor 官方文档编写,遵循 Creative Commons Attribution-ShareAlike 4.0 International License 协议。

文档反馈