swift - reduce简介

news2025/1/18 10:49:09

reduce

减少,降低;(烹调中)使变浓稠,收汁;<美>节食减肥;使沦为,使陷入(不好的境地);迫使,使不得不(做);(通过破裂、燃烧等)使变成,使化为;归纳,简化;将分数约到(最小项);(使)进行还原反应;减薄(底片或图片);(语音)弱化;使(脱臼,断骨)复位;<古>攻克,征服(尤指围攻并占领城镇或要塞)

基础:

reduce函数是,一个可以设置一个初始值的函数,并且可以返回两个结果变量,我们一般称为result,currentCase

result: 一般是指上次得到的结果之和

currentCase: 一般指本次遍历的对象

举例:

let prices = [20,30,40]
let sum = prices.reduce(0) { $0 + $1 }
print(sum)

//90

注意: reduce(0) 这里reduce(0)是什么初始值,我们函数就会返回什么结果。

let prices = [20,30,40]
let sum = prices.reduce(100) { $0 + $1 }
print(sum)

//190

计算数组元素的出现次数

let students = [
    Student(id: "991", name: "Jessica", gender: .female, age: 20),
    Student(id: "992", name: "James", gender: .male, age: 25),
    Student(id: "993", name: "Mary", gender: .female, age: 19),
    Student(id: "994", name: "Edwin", gender: .male, age: 27),
    Student(id: "995", name: "Stacy", gender: .female, age: 18),
    Student(id: "996", name: "Emma", gender: .female, age: 22),
]

enum Gender {
    case male
    case female
}

struct Student {
    let id: String
    let name: String
    let gender: Gender
    let age: Int
}

let result = students.reduce(into: (male: 0, female: 0)) {
// 或者
// let result = students.reduce(into: (0, 0)) {
    if $1.gender == .male {
        $0.0 += 1
    } else {
        $0.1 += 1
    }
}

print("male: result \(result.0) female: \(result.1)")
print("male: result \(result.male) female: \(result.female)")

获取数组内某个model属性的总和

我们想要获得学生年龄的总和

这个就比较简单了,单纯的年龄相加就可以了,代码如下:

let result = students.reduce(0) {
    $0 + $1.age
}

print(result) // 131

对于数组元素类型是支持加法运算符 ( +) 的类型,我们可以通过省略简写参数名称来进一步简化它:

let sum1 = [2, 3, 4].reduce(0, +)          // Output: 9
let sum2 = [5.5, 10.7, 9.43].reduce(0, +)  // Output: 44.435
let sum3 = ["a","b","c"].reduce("", +)     // Output: "abc"

从数组中获取一些随机元素

从数组中获取一些随机元素曾经是一种难以实现的算法,因为我们需要处理各种边缘情况。
现在借助Swift数组中的shuffled() 和 prefix(_:)函数,这个操作变得非常容易实现。
以下是从students数组中随机挑选 3 名学生的方法:

// Randomize all elements within the array
let randomized = students.shuffled()

// Get the first 3 elements in the array
let selected = randomized.prefix(3)
let selected2 = randomized.prefix(13)
print(selected)
print(selected2)

这种方法的一个好处是,即使我们尝试获取的元素数量超过数组的总元素,它也不会触发索引超出范围异常。
结果

[SwiftUnitTest.Student(id: "996", name: "Emma", gender: SwiftUnitTest.Gender.female, age: 22), 
SwiftUnitTest.Student(id: "991", name: "Jessica", gender: SwiftUnitTest.Gender.female, age: 20), 
SwiftUnitTest.Student(id: "992", name: "James", gender: SwiftUnitTest.Gender.male, age: 25)]


[SwiftUnitTest.Student(id: "996", name: "Emma", gender: SwiftUnitTest.Gender.female, age: 22), 
SwiftUnitTest.Student(id: "991", name: "Jessica", gender: SwiftUnitTest.Gender.female, age: 20),
SwiftUnitTest.Student(id: "992", name: "James", gender: SwiftUnitTest.Gender.male, age: 25), 
SwiftUnitTest.Student(id: "995", name: "Stacy", gender: SwiftUnitTest.Gender.female, age: 18), 
SwiftUnitTest.Student(id: "993", name: "Mary", gender: SwiftUnitTest.Gender.female, age: 19), 
SwiftUnitTest.Student(id: "994", name: "Edwin", gender: SwiftUnitTest.Gender.male, age: 27)]

我们可以看到随机可以随到最大的数6就结束了,并没有一定要完成到 13

按条件对数组元素进行分组

假设我们想按student name的第一个字母对学生进行分组。传统上,我们必须手动遍历数组中的每个元素, 并相应地对它们进行分组。

struct Student {
    let id: String
    let name: String
    let gender: Gender
    let age: Int
}

现在,在Dictionary(grouping:by:)初始化程序的帮助下,我们可以在不使用for-in循环的情况下实现这一点。就是这样:

let groupByFirstLetter = Dictionary(grouping: students) { student in
    return student.name.first!
}

/*
 PrintLog:
 [
    ["J": [SwiftUnitTest.Student(id: "991", name: "Jessica", gender: SwiftUnitTest.Gender.female, age: 20), SwiftUnitTest.Student(id: "992", name: "James", gender: SwiftUnitTest.Gender.male, age: 25)],
    "M": [SwiftUnitTest.Student(id: "993", name: "Mary", gender: SwiftUnitTest.Gender.female, age: 19)], 
    "E": [SwiftUnitTest.Student(id: "994", name: "Edwin", gender: SwiftUnitTest.Gender.male, age: 27), SwiftUnitTest.Student(id: "996", name: "Emma", gender: SwiftUnitTest.Gender.female, age: 22)], 
    "S": [SwiftUnitTest.Student(id: "995", name: "Stacy", gender: SwiftUnitTest.Gender.female, age: 18)]]

 ]
 */

从上面的示例代码中可以看出,初始化程序将生成一个类型为 的字典[KeyType: Student]。
KEY = 每个Student 的name 的第一个字母 ,
如果我们想按标准对学生进行分组, 并在多部分表格视图中显示他们,这将特别有用。
我们甚至可以通过Swift 中使用速记参数名称或者健路语法来进一步简化

// Using shorthand argument names
let groupByFirstLetter = Dictionary(grouping: students, by: { $0.name.first! })

// Using key path syntax
let groupByFirstLetter = Dictionary(grouping: students, by: \.name.first!)

reduce(into:)

reduce(into:)方法也是一个实用方法,主要作用是遍历数组中的元素,把它们into到另一个对象中,示例:

如下有一个数组,把偶数放一个数组中,把奇数放一个数组中:

let nums = [1,2,3,4,5]
let result = nums.reduce(into: [[],[]]) { arr, num in
    arr[num%2].append(num)
}
//或者
let result = nums.reduce(into: [[],[]]) {
    $0[$1%2].append($1)
}
print(result[0]) // [2, 4]
print(result[1]) // [1, 3, 5]

这里into:后面的[[], []]是一个二级数组,这个二维数组即闭包中的arr, 而闭包中的num是nums数组中每一个值,遍历后把这个二维数组返回 (由函数原型的inout可知,返回的其实就是into:参数,本例中即二维数组)

func reduce<Result>(into: Result, _ updateAccumulatingResult: (inout Result, Element) throws -> ()) -> Result

为了更方例理解,展开为:

temp[1].append(1) //1%2 = 1/2 left 1 [[][1]]
temp[0].append(2) //2%2 = 2/2 left 0 [[2][1]]
temp[1].append(3) //3%2 = 3/2 = 1 left 1 [[2][1,3]]
temp[0].append(4) //4%2 = 4/2 left 0 [[2,4][1,3]]
temp[1].append(5) //5%2 = 5/2 = 2 left 1 [[2,4][1,3,5]]

示例参考:https://stackoverflow.com/questions/62103658/how-do-you-use-reduceinto-in-swift

再来看一个示例:

// 统计下面的字符串中每个字符的使用次数
let letters = "abracadabra"
let letterCount = letters.reduce(into: [:]) { counts, letter in
    counts[letter, default: 0] += 1
}
print(letterCount) // ["a": 5, "r": 2, "c": 1, "b": 2, "d": 1]

或者

let letters = "abracadabra"
let letterCount = letters.reduce(into:[:]) {
	//$0[$1] = ($0[$1] ?? 0) +1 
	$0[$1, default: 0] += 1
}
print(letterCount) // ["a": 5, "r": 2, "c": 1, "b": 2, "d": 1]

在这里插入图片描述

其实就是遍历字符串,然后把它们into到字典[:]中

讲解为啥使用default:

$0[$1, default: 0] += 1

使用了 Swift 字典的子脚本支持。其中 default: 关键字允许当字典中不存在键时返回一个默认值。
那么为什么要用 default: 呢?因为在统计的时候,字母第一次出现时字典中并没有对应键。如果直接写成:

$0[$1] += 1

首次出现时因为字典没有这个键,会导致崩溃。
使用 default: 可以确保每次统计都至少从 0 开始,不会因为 KeyError 崩溃。
那么它具体的作用就是:
第一次出现该字母时,会返回默认值 0,并把对应键值对添加入字典
后续出现该字母时,直接累加计数器
所以 default: 保证了程序的鲁棒性,可以正常统计首次出现的字母,避免崩溃。
另一种写法是使用 nil 合并运算符:

$0[$1] = ($0[$1] ?? 0) + 1

也可以避免首次出现时的崩溃。
但使用 default: 更简洁清晰一些。

还有个示例:

struct Person {
    enum Gender {
        case male
        case female
    }
    
    var name = ""
    var age = 0
    var gender = Gender.female
}

let dataSource = [Person(name: "鸡大宝", age: 38, gender: .male),
                  Person(name: "江主任", age: 50, gender: .female),
                  Person(name: "可乐", age: 10, gender: .female),
                  Person(name: "伍六七", age: 16, gender: .male),
                  Person(name: "梅花十三", age: 20, gender: .female)]

// 获取数据源中男女各多少人
let genderCount = dataSource.reduce(into: [Person.Gender: Int]()) { result, person in
    result[person.gender, default: 0] += 1
}
let maleCount = genderCount[Person.Gender.male] // 2
let femaleCount = genderCount[Person.Gender.female] // 3
print(maleCount ?? 0) // 2
print(femaleCount ?? 0) // 3

参考摘录:
https://juejin.cn/post/6983286929882087454
https://www.jianshu.com/p/781d5f6020b3
https://juejin.cn/post/7066782801928044581

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1416468.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】输入输出、缺省参数、函数重载

目录 C的输入和输出 缺省参数 概念 缺省参数的分类 全缺省参数 半缺省参数 函数重载 概念 C支持函数重载的原理--名字修饰 C的输入和输出 #include<iostream> // std是C标准库的命名空间名&#xff0c;C将标准库的定义实现都放到这个命名空间中 using namespace …

BKP备份寄存器、RTC实时时钟

目录 1. BKP (Backup Registers)备份寄存器 2. RTC (Real Time Clock)实时时钟 1. BKP (Backup Registers)备份寄存器 BKP可用于存储用户应用程序数据。当VDD (2.0-3.6V)电源被切断,他们仍然由VBAT (1.8-3.6V)维持供电。当系统在待机模式下被唤醒&#xff0c;或系统复位或…

【大数据】Flink 架构(一):系统架构

Flink 架构&#xff08;一&#xff09;&#xff1a;系统架构 1.Flink 组件1.1 JobManager1.2 ResourceManager1.3 TaskManager1.4 Dispatcher 2.应用部署2.1 框架模式2.2 库模式 3.任务执行4.高可用设置4.1 TaskManager 故障4.2 JobManager 故障 Flink 是一个用于状态化并行流处…

BeanUtils和BeanCopier性能复制Bean工具比较

文章目录 一、前言二、实验三、原理1、BeanUtils2、BeanCopier 四、总结 一、前言 我们本篇比较的是复制Bean对象的工具&#xff0c;分别是org.springframework.beans.BeanUtils和 net.sf.cglib.beans.BeanCopier 二、实验 import net.sf.cglib.beans.BeanCopier; import org…

部署LNMP、Nginx+FastCGI、Nginx地址重写语法,地址重写应用案例

1 案例1&#xff1a;部署LNMP环境 1.1 问题 安装部署LNMP环境实现动态网站解析 静态网站 在不同环境下访问&#xff0c;网站内容不会变化 动态网站 在不同环境下访问&#xff0c;网站内容有可能发生变化 安装部署Nginx、MariaDB、PHP、PHP-FPM&#xff1b;启动Nginx、Mari…

java—AWT

AWT 课程&#xff1a;1、GUI编程简介_哔哩哔哩_bilibili 一.介绍 包含了很多类和接口&#xff01;GUI&#xff01;元素&#xff1a;窗口、按钮、文本框java.awt 二.窗口 1.构造 2.方法 // 实例化frame类Frame frame new Frame("这个一个框");// 设置可见性frame.…

游戏设计模式

单列模式 概念 单例模式是一种创建型设计模式&#xff0c;可以保证一个类只有一个实例&#xff0c;并提供一个访问该实例的全局节点。 优点 可以派生&#xff1a;在单例类的实例构造函数中可以设置以允许子类派生。受控访问&#xff1a;因为单例类封装他的唯一实例&#xf…

Cyberdog2 docker环境软件源无法被验证问题

搭建docker系统后更新软件源sudo apt-get update出现异常 经过查询GPT&#xff0c;使用如下方式成功解决 从keyserver.ubuntu.com获取缺失的公钥&#xff0c;并添加到apt-key中。具体命令如下&#xff1a; gpg --keyserver keyserver.ubuntu.com --recv-keys F42ED6FBAB17C6…

C++的关键字,命名空间,缺省参数,函数重载以及原理

文章目录 前言一、C关键字(C98)二、命名空间命名空间介绍命名空间的使用 三、C输入【cin】& 输出【cout】四、缺省参数缺省参数概念缺省参数分类缺省参数的使用小结一下 五、函数重载函数重载介绍函数重载类型 六、C支持函数重载的原理--名字修饰(name Mangling)【重点】 前…

【开源】基于JAVA语言的智慧社区业务综合平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 业务类型模块2.2 基础业务模块2.3 预约业务模块2.4 反馈管理模块2.5 社区新闻模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 业务类型表3.2.2 基础业务表3.2.3 预约业务表3.2.4 反馈表3.2.5 社区新闻表 四、系统展…

[BUUCTF]-PWN:hitcon2014_stkof解析

又是一道堆题&#xff0c;先看保护 关键信息&#xff0c;64位&#xff0c;没开pie。再看ida 大致就是alloc创建堆块&#xff0c;free释放堆块&#xff0c;fill填充堆块内容&#xff0c;以及一个看起来没啥用的函数&#xff0c;当然我也没利用这个函数去解题 这里有两种解法 解…

Python tkinter (6) Listbox

Python的标准Tk GUI工具包的接口 tkinter系列文章 python tkinter窗口简单实现 Python tkinter (1) —— Label标签 Python tkinter (2) —— Button标签 Python tkinter (3) —— Entry标签 Python tkinter (4) —— Text控件 GUI 目录 Listbox 创建listbox 添加元素…

Java版大厂算法题1——数字颠倒

问题描述 输入一个整数&#xff0c;将这个整数以字符串的形式逆序输出&#xff0c;程序不考虑负数的情况&#xff0c;若数字含有0&#xff0c;则逆序形式也含有0。如果输入为100&#xff0c;则输出为001。 数据范围&#xff1a;0<n<(2^30)-1 * 输入描述&#xff1a;输入…

2023启示录|虚拟人这一年

图片&#xff5c;《银翼杀手 2049》剧照 作者丨程心 编辑丨罗辑 2023 年&#xff0c;大模型 “救活” 了很多行业&#xff0c;其中最为反转的&#xff0c;就是把虚拟数字人&#xff08;以下简称虚拟人&#xff09;从活死人墓里拉了出来。 还没开年&#xff0c;在 2022 年火…

保姆级教学:Java项目从0到1部署到云服务器

目录 1、明确内容 2、apt 2.1、apt 语法 2.2、常用命令 2.3、更新apt 3、安装JDK17 4、安装MySQL 4.1、安装 4.2、检查版本及安装位置 4.3、初始化MySQL配置⭐ 4.4、检查状态 4.5、配置远程访问⭐ 4.6、登录MySQL 4.7、测试数据库 4.8、设置权限与密码⭐ 5、安…

基于Python flask MySQL 猫眼电影可视化系统设计与实现

1 绪论 1.1 设计背景及目的 猫眼电影作为国内知名的电影信息网站&#xff0c;拥有海量的电影信息、票房数据和用户评价数据。这些数据对于电影市场的研究和分析具有重要意义。然而&#xff0c;由于数据的复杂性和数据来源的多样性&#xff0c;如何有效地采集、存储和展示这些数…

0127-2-Vue深入学习5—Vue-Router路由模式

1、Vue-Router三种路由模式&#xff1a; hash&#xff1a;#️⃣使用URL hash 值来做路由&#xff0c;支持所有路由器&#xff1b;history:&#x1f4d6;依赖HTML5 History API和服务器配置&#xff1b;abstract:⛓支持所有JS运行环境&#xff0c;Node.js服务端&#xff1b; 1.1…

基于springboot+vue+mysql+mybatis的博客系统源码+数据库

pb-cms 介绍 博客系统&#xff0c;架构&#xff1a;springbootvuemysqlmybatis 软件架构 软件架构说明 系统截图 技术选型 技术版本说明Spring Boot2.1.6MVC核心框架Spring Security oauth22.1.5认证和授权框架MyBatis3.5.0ORM框架MyBatisPlus3.1.0基于mybatis&#xff0…

HCIA-HarmonyOS设备开发认证-3.内核基础

目录 前言目标一、进程与线程待续。。。 前言 对于任何一个操作系统而言&#xff0c;内核的运行机制与原理是最为关键的部分。本章内容从多角度了解HarmonyOS的内核运行机制&#xff0c;涵盖进程与线程的概念&#xff0c;内存管理机制&#xff0c;网络特性&#xff0c;文件系统…

高级CPU(提高CPU运行速度)

晶体管 早期是加快晶体管切换速度,来提升CPU速度 增加电路 给CPU专门的除法电路其他电路来做复杂操作 缓存&#xff08;cache&#xff09; 给CPU加缓存&#xff08;cache&#xff09;,提高数据存取速度,更快送给CPU&#xff0c;因为处理器里空间不大所以缓存一般只有KB或M…