2、Python数据结构 - 从Java集合到Python容器

56 阅读5分钟

Python数据结构 - 从Java集合到Python容器

1. Python的主要数据结构概览

作为Java开发者,您已经熟悉了ArrayList、HashMap等集合类。Python也有类似的数据结构,但更加简洁和灵活。

Python数据结构关系图

graph TD
    A[Python数据结构] --> B[可变数据结构]
    A --> C[不可变数据结构]
    
    B --> D[列表 List]
    B --> E[字典 Dictionary]
    B --> F[集合 Set]
    
    C --> G[元组 Tuple]
    C --> H[冻结集合 Frozenset]
    
    D --> I[有序]
    D --> J[可索引]
    D --> K[可重复元素]
    
    E --> L[键值对]
    E --> M[无序]
    E --> N[键唯一]
    
    F --> O[无序]
    F --> P[唯一元素]
    F --> Q[可进行集合运算]
    
    G --> R[有序]
    G --> S[可索引]
    G --> T[可重复元素]
    G --> U[不可修改]
    
    H --> V[唯一元素]
    H --> W[不可修改]
    H --> X[可作为字典键或集合元素]
    
    style A fill:#f9f,stroke:#333,stroke-width:2px
    style B fill:#bbf,stroke:#333,stroke-width:2px
    style C fill:#dfd,stroke:#333,stroke-width:2px
    style D fill:#fdd,stroke:#333,stroke-width:2px
    style E fill:#ddf,stroke:#333,stroke-width:2px
    style F fill:#ffd,stroke:#333,stroke-width:2px
    style G fill:#dff,stroke:#333,stroke-width:2px
    style H fill:#fdf,stroke:#333,stroke-width:2px

2. 列表(List) - Python的"ArrayList"

列表是Python中最常用的数据结构,类似于Java的ArrayList。

创建列表

# 创建空列表
empty_list = []
# 创建带初始值的列表
numbers = [1, 2, 3, 4, 5]
mixed = [1, "Hello", 3.14, True]

列表操作

fruits = ["apple", "banana", "cherry"]

# 访问元素
print(fruits[0])  # 输出: apple

# 修改元素
fruits[1] = "blueberry"
print(fruits)  # 输出: ['apple', 'blueberry', 'cherry']

# 添加元素
fruits.append("orange")  # 在末尾添加
fruits.insert(1, "mango")  # 在指定位置插入
print(fruits)  # 输出: ['apple', 'mango', 'blueberry', 'cherry', 'orange']

# 删除元素
fruits.remove("cherry")  # 删除指定元素
popped = fruits.pop()  # 删除并返回最后一个元素
del fruits[0]  # 删除指定位置的元素
print(fruits)  # 输出: ['mango', 'blueberry']

# 列表长度
print(len(fruits))  # 输出: 2

# 检查元素是否存在
print("mango" in fruits)  # 输出: True

列表切片

Python的切片操作非常强大,没有直接的Java等价物:

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 基本切片: [start:end] (不包括end)
print(numbers[2:5])  # 输出: [2, 3, 4]

# 省略起始索引,默认为0
print(numbers[:5])  # 输出: [0, 1, 2, 3, 4]

# 省略结束索引,默认到列表末尾
print(numbers[5:])  # 输出: [5, 6, 7, 8, 9]

# 负索引表示从末尾开始计数
print(numbers[-3:])  # 输出: [7, 8, 9]

# 步长切片: [start:end:step]
print(numbers[::2])  # 输出: [0, 2, 4, 6, 8]
print(numbers[1::2])  # 输出: [1, 3, 5, 7, 9]

# 负步长可以反转列表
print(numbers[::-1])  # 输出: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

列表推导式

列表推导式是Python的一个强大特性,可以简洁地创建新列表:

# 创建平方数列表
squares = [x**2 for x in range(10)]
print(squares)  # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 带条件的列表推导式
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares)  # 输出: [0, 4, 16, 36, 64]

# Java等价写法
/*
List<Integer> squares = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    squares.add(i * i);
}
*/

3. 元组(Tuple) - 不可变列表

元组类似于列表,但是不可修改(immutable)。Java中没有直接等价物,最接近的可能是使用final的数组或List。

# 创建元组
coordinates = (10, 20)
person = ("John", 30, "New York")

# 访问元素
print(coordinates[0])  # 输出: 10
print(person[1])  # 输出: 30

# 尝试修改会引发错误
# coordinates[0] = 15  # TypeError: 'tuple' object does not support item assignment

# 单元素元组需要逗号
singleton = (1,)  # 这是一个元组
not_tuple = (1)  # 这只是一个被括号包围的整数

# 元组解包
name, age, city = person
print(name)  # 输出: John
print(city)  # 输出: New York

# 交换变量值
a, b = 1, 2
a, b = b, a  # 现在a=2, b=1

4. 字典(Dictionary) - Python的"HashMap"

字典类似于Java的HashMap,存储键值对。

# 创建字典
empty_dict = {}
user = {
    "name": "John",
    "age": 30,
    "city": "New York"
}

# 访问值
print(user["name"])  # 输出: John

# 修改值
user["age"] = 31
print(user)  # 输出: {'name': 'John', 'age': 31, 'city': 'New York'}

# 添加新键值对
user["email"] = "john@example.com"
print(user)  # 输出: {'name': 'John', 'age': 31, 'city': 'New York', 'email': 'john@example.com'}

# 删除键值对
del user["city"]
email = user.pop("email")  # 删除并返回值
print(user)  # 输出: {'name': 'John', 'age': 31}

# 检查键是否存在
print("name" in user)  # 输出: True
print("city" in user)  # 输出: False

# 获取所有键和值
print(user.keys())  # 输出: dict_keys(['name', 'age'])
print(user.values())  # 输出: dict_values(['John', 31])
print(user.items())  # 输出: dict_items([('name', 'John'), ('age', 31)])

# 安全获取值(不存在时返回默认值)
print(user.get("city", "Unknown"))  # 输出: Unknown

字典推导式

# 创建平方映射字典
squares = {x: x**2 for x in range(6)}
print(squares)  # 输出: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 反转键值对
inverted = {v: k for k, v in squares.items()}
print(inverted)  # 输出: {0: 0, 1: 1, 4: 2, 9: 3, 16: 4, 25: 5}

5. 集合(Set) - Python的"HashSet"

集合是无序的、不重复元素的集合,类似于Java的HashSet。

# 创建集合
empty_set = set()  # 注意:{}创建的是空字典,不是空集合
fruits = {"apple", "banana", "cherry"}

# 添加元素
fruits.add("orange")
fruits.add("apple")  # 重复元素不会被添加
print(fruits)  # 输出: {'orange', 'banana', 'cherry', 'apple'}

# 删除元素
fruits.remove("banana")  # 如果元素不存在,会引发KeyError
fruits.discard("mango")  # 如果元素不存在,不会引发错误
print(fruits)  # 输出: {'orange', 'cherry', 'apple'}

# 集合操作
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}

# 并集
print(set1 | set2)  # 输出: {1, 2, 3, 4, 5, 6, 7, 8}
print(set1.union(set2))  # 同上

# 交集
print(set1 & set2)  # 输出: {4, 5}
print(set1.intersection(set2))  # 同上

# 差集
print(set1 - set2)  # 输出: {1, 2, 3}
print(set1.difference(set2))  # 同上

# 对称差集(在一个集合中但不在两个集合中)
print(set1 ^ set2)  # 输出: {1, 2, 3, 6, 7, 8}
print(set1.symmetric_difference(set2))  # 同上

# 检查子集和超集
set3 = {4, 5}
print(set3.issubset(set1))  # 输出: True
print(set1.issuperset(set3))  # 输出: True

6. Java集合与Python数据结构对比

JavaPython主要区别
ArrayListListPython列表更灵活,可以存储不同类型的元素
LinkedListcollections.dequePython没有内置的链表,但deque提供类似功能
HashMapDictionaryPython字典的键可以是任何不可变类型
HashSetSet功能基本相同
TreeMapcollections.OrderedDictPython 3.7+的字典默认保持插入顺序
ArraysList/TuplePython没有固定大小的数组

7. 练习:数据结构转换

将以下Java代码转换为Python:

import java.util.*;

public class StudentManager {
    public static void main(String[] args) {
        // 创建学生列表
        List<String> students = new ArrayList<>();
        students.add("Alice");
        students.add("Bob");
        students.add("Charlie");
        
        // 创建成绩映射
        Map<String, Integer> scores = new HashMap<>();
        scores.put("Alice", 95);
        scores.put("Bob", 85);
        scores.put("Charlie", 90);
        
        // 打印所有学生的成绩
        for (String student : students) {
            System.out.println(student + ": " + scores.get(student));
        }
        
        // 计算平均分
        int sum = 0;
        for (Integer score : scores.values()) {
            sum += score;
        }
        double average = (double) sum / scores.size();
        System.out.println("Average score: " + average);
    }
}

Python解决方案:

def main():
    # 创建学生列表
    students = ["Alice", "Bob", "Charlie"]
    
    # 创建成绩映射
    scores = {
        "Alice": 95,
        "Bob": 85,
        "Charlie": 90
    }
    
    # 打印所有学生的成绩
    for student in students:
        print(f"{student}: {scores[student]}")
    
    # 计算平均分
    average = sum(scores.values()) / len(scores)
    print(f"Average score: {average}")

if __name__ == "__main__":
    main()

8. 今日总结

  • Python的列表(List)类似于Java的ArrayList,但更灵活
  • 元组(Tuple)是不可变的列表,适合表示固定结构的数据
  • 字典(Dictionary)类似于Java的HashMap,但键可以是任何不可变类型
  • 集合(Set)类似于Java的HashSet,用于存储唯一元素
  • Python的列表切片和推导式是非常强大的特性,没有直接的Java等价物

9. 明日预告

明天我们将学习Python的控制流和函数,包括条件语句、循环、函数定义和Lambda表达式,以及它们与Java的对比。