likes
comments
collection
share

用 NBA 的方式打开数组、元组、Map、Set🏀🏀🏀

作者站长头像
站长
· 阅读数 3

几天前,一位朋友问我如何防止数组中键值的重复。我向他解释,有其他类型的集合可以使用,每一种都适应于特定的使用场景。由于我是 NBA 的忠实粉丝,我尝试找了一种简单的方式,通过篮球的语境来解释各种数据结构。

在篮球比赛中,策略是至关重要的。在恰当的时机使用合适的球员能够改变整场比赛的局势。类似地,选择合适的数据结构——无论是数组、元组、映射还是集合——能够极大地影响编程中的"比赛"。现在,我们将深入探讨每种数据结构,理解在何种情况下使用它们,何时不宜使用它们,以及它们各自的缺点是什么。

那么,我们开始吧:

数组

数组犹如一支篮球队的阵容名单,其中列举了所有球员的名字。随着时间的推移,我们可以根据需要添加或者移除球员。

例如,今年的 NBA 赛季已经开打了,我们来选一个心中的球队组合吧:

const teamRoster: string[] = ["LeBron James", "Stephen Curry", "Kevin Durant"];

这种方式有优点也有缺点,那么我们来看看它的优缺点。

  • 优点:

    • 动态大小,数组可以根据需要动态调整大小。
    • 直接访问,我们可以使用索引(位置)直接访问元素(例如,球员)。
  • 缺点:类型检查不严格,数组中不同位置的元素可能没有严格的类型检查。

  • 使用场景: 当你有一组相似的项时,例如,所有的控球后卫或所有的新秀球员。

  • 避免使用场景:当你需要一个固定大小的集合或处理多种数据类型的情况时。

元组

元组就像为特定位置指定确切的球员一样;每个位置都是预先定义的。

例如:固定的首发阵容,位置和球员都是预先定义的。

const startingLineup: [string, string, string, string, string] = [
  "Point Guard",
  "Shooting Guard",
  "Small Forward",
  "Power Forward",
  "Center",
];

这种方式有优点也有缺点,那么我们来看看它的优缺点。

  • 优点:

    • 严格的结构,对固定大小的数据提供一个严格的结构。
    • 位置具有特定类型,每一个位置(索引)都有一个特定的类型。
  • 缺点:不够灵活,无法轻松改变阵容大小。

  • 适用场景:当位置和球员是固定的,比如一个特定比赛的首发五人。

  • 避免使用场景: 球队阵容大小可变或阵容需要变动的情况。

Maps

Maps 就像一支球队的球衣号码。每个球员(值)都有一个唯一的球衣号码(键)。

例如:将每个球员与其球衣号码相关联。如下代码所示:

const jerseyNumbers = new Map<string, number>();
jerseyNumbers.set("LeBron James", 6);
jerseyNumbers.set("Stephen Curry", 30);

这种方式有优点也有缺点,那么我们来看看它的优缺点。

  • 优点:

    • 键值灵活,我们可以有任意键和值。
    • 保持插入顺序,它保留了插入数据的顺序。
  • 缺点:

    • 可能过于复杂,对于简单的键值关联来说,使用它可能有些过于复杂。
  • 适用场景:当将球员与统计数据、奖项或任何特定数据关联时。

  • 避免使用场景:简单列表的场合或一个对象就足够的场合。

Sets

Sets 就像全明星赛名单。没有球员会被选中两次;每个人都是独一无二的。

例如:入选全明星赛的一组球员。如下代码所示:

let allStars = new Set<string>();
allStars.add("LeBron James");
allStars.add("LeBron James"); // 重复了

这种方式有优点也有缺点,那么我们来看看它的优缺点。

  • 优点:

    • 确保唯一性,保证每个元素不会重复。
    • 快速成员检查,能够迅速检查一个元素是否属于集合。

缺点:

  • 无键值关联,不支持键值对的存储。

  • 适用场景:用于存储需要确保元素唯一性的集合,如篮球名人堂成员或 MVP 获得者等。

避免使用场景:当重复元素是可以接受的或需要键值对关联的情况下。

使用场景

基于上面中讨论到的,让我们创建一个简单的 TypeScript 示例,结合篮球运动员和不同的数据结构(数组,集合,映射等)。

假设我们正在开发一个简单的 NBA 球队管理系统。我们要追踪不同的球员,每个球员的基本信息,得分,助攻等统计信息,以及每年的 MVP 得主等。

场景:NBA 球队管理系统

  1. 球队名单 (Array) 用于记录整个球队的球员名单。球员可以加入和离开队伍。
const teamRoster: string[] = [
  "LeBron James",
  "Anthony Davis",
  "Russell Westbrook",
];
  1. 比赛首发阵容 (Tuple) 对于特定比赛,我们知道首发位置和球员名称,这里可以用元组存储。
type StartingFive = [string, string, string, string, string];
const gameStartingFive: StartingFive = [
  "LeBron James",
  "Anthony Davis",
  "Russell Westbrook",
  "Dwight Howard",
  "Kent Bazemore",
];
  1. 球员统计 (Map) 用于存储每个球员的具体统计信息。键是球员的名字,值是一个对象,包含该球员的各种统计。
const playerStats: Map<
  string,
  { points: number; assists: number; rebounds: number }
> = new Map();
playerStats.set("LeBron James", { points: 25, assists: 9, rebounds: 8 });
  1. 年度 MVP (Set) 用于存储每年的 MVP 得主。因为 MVP 是独一无二的,所以我们使用集合来保证不会有重复的得主。
const mvps: Set<string> = new Set();
mvps.add("LeBron James").add("Stephen Curry");

使用示例

  1. 添加新球员到球队名单
teamRoster.push("Carmelo Anthony");
  1. 更新比赛首发阵容
gameStartingFive = [
  "LeBron James",
  "Anthony Davis",
  "Russell Westbrook",
  "Carmelo Anthony",
  "Kent Bazemore",
];
  1. 更新球员统计
playerStats.set("Carmelo Anthony", { points: 20, assists: 3, rebounds: 6 });
  1. 添加新 MVP
mvps.add("Giannis Antetokounmpo");

以上,我们根据特定的用例和场景使用了不同的数据结构。希望这个示例可以帮助理解如何在实际项目中应用这些基本的数据结构。

参考

总结

通过上面的内容,我们应该知道:

  • 数组:灵活地存储球队名单,可以动态调整球员名单的大小,便于添加或删除球员。
  • 元组:为固定大小和位置的数据(比如比赛的首发阵容)提供了一个严格的结构。
  • 映射:通过键值对存储数据,使我们能够将球员名与其相关的统计数据相关联。
  • 集合:用来存储唯一项(例如每年的 MVP 得主),保证没有重复的值。

这些数据结构的使用依赖于它们各自的特性和使用场景,确保数据组织和管理的有效性和效率。在实际应用中,合理选择和使用数据结构能够极大地影响代码的可读性、易用性和性能。希望这个 NBA 球队的简单例子能够帮助你理解这些基本数据结构的实际应用方式。

最后分享两个我的两个开源项目,它们分别是:

这两个项目都会一直维护的,如果你也喜欢,欢迎 star 🚗🚗🚗