swift - reduce简介

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

根据内容指定条件下数值的相加

例如下面的例子,获取100秒的时间内可获取的奖励的数量

struct RewordModel {
	let time: Int
    let reward: Int
}
    
let data: [RewordModel] = [
	RewordModel(time: 20, reward: 50),
    RewordModel(time: 30, reward: 100),
    RewordModel(time: 70, reward: 200),
]
let targetTime = 100
let total = data.reduce(into: (time: 0, amount: 0)) {
	if Int($0.0) + $1.time < targetTime {
    $0.0 += $1.time 
     $0.1 += $1.reward
}
}
print(total)
// 打印 150 (即50+100)

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

自然语言处理中的词云生成

一.词云的介绍 自然语言处理中的词云技术是文本可视化的一种形式&#xff0c;用于展示文本数据中词语的频率分布。以下是词云在自然语言处理中的基本介绍和发展&#xff1a; 起源和发展&#xff1a; 词云的概念最初来源于信息可视化领域&#xff0c;用于将文本中的关键词以视…

脉宽调制器

1. pwm脉宽调制器 脉宽调制器: 一种硬件设备, 用于 动态调制 方波 的 一些属性, 方波的周期,频率,占空比 占空比? : 有效电平占 整个周期的比值 可以使用PWM 控制功率, 控制频率 用于 开关电源 或 逆变器 1.1 原理 PWM原理: 如图所示 本质就是一个定时器: 由原理…

游戏开发丨基于Pygame的AI版贪吃蛇小游戏

文章目录 写在前面需求分析程序设计程序分析运行结果系列文章写在后面 写在前面 本期内容 基于pygame的AI版贪吃蛇小游戏 所需环境 pythonpycharm或anacondapygame 下载地址 https://download.csdn.net/download/m0_68111267/88789665 需求分析 本游戏使用Pygame模块开…

FL Studio21.2.2中文学生版免费下载(支持简体中文,支持苹果M1/M2处理器)

今天小编给大家带来的是一款功能非常强大的音乐创作编辑软件它就是(水果软件)。使用FL Studio21中文版可以轻松帮我们制作自己的音乐唱片&#xff0c;拥有强大且专业的创作工具&#xff0c;COCO玛奇朵为您提供FL Studio(水果软件)2024免费下载&#xff0c; FL Studio 21 Win-安…

ASCP电气防火限流式保护器功能以及应用场景

功能&#xff1a; ASCP200型电气防火限流式保护器可有效克服传统断路器、空气开关和监控设备存在的短路电流大、切断短路电流时间长、短路时产生的电弧火花大&#xff0c;以及使用寿命短等弊端&#xff0c;发生短路故障时&#xff0c;能以微秒级速度快速限制短路电流以实现灭弧…

C++:异常体系

异常体系 异常1.C语言传统的处理错误的方式2.C异常概念3.异常的使用3.1异常的抛出和捕获3.2 异常的重新抛出3.3异常安全3.4 异常规范 4.C标准库的异常体系5.异常的优缺点 异常 1.C语言传统的处理错误的方式 终止程序&#xff0c;如assert&#xff0c;缺陷&#xff1a;用户难以…

深度视频恢复软件推荐,轻松恢复视频文件!

“我在电脑上保存了一些视频&#xff0c;但在清理时却不小心将这些视频删除了&#xff0c;有什么方法可以恢复删除的视频吗&#xff1f;希望大家给我推荐一些好用的方法。” 随着科技的飞速发展&#xff0c;数字媒体已经成为了我们生活中不可或缺的一部分。然而&#xff0c;数字…

17K star!开源免费的离线OCR工具

平时工作中,总会遇到想对图片内文字进行处理的情况,我们就来介绍一款开源、免费的离线OCR工具,它就是:Umi-OCR。 关于 Umi-OCR Umi-OCR是开源、免费的离线OCR软件。支持截屏/粘贴/批量导入图片,段落排版/排除水印,扫描/生成二维码。项目内置多国语言库,方便切换。 Umi-…

【Python时序预测系列】基于LSTM实现单变量时间序列预测(源码)

一、引言 前文回顾&#xff1a; 【Python时序预测系列】基于Holt-Winters方法实现单变量时间序列预测&#xff08;源码&#xff09; 【Python时序预测系列】基于ARIMA法实现单变量时间序列预测&#xff08;源码&#xff09; 【Python时序预测系列】基于SARIMA实现单变量时间…

超声波清洗机买哪款比较好?四款公认好用超声波清洗机

超声波清洗机好用吗&#xff1f;好多人都说是普通的清洁工具买回家就是浪费钱&#xff0c;真心不建议购买&#xff0c;但其实&#xff0c;手动清洗眼镜的话会比较容易损坏镜片&#xff0c;一副眼镜比较普通的也要上几百了&#xff0c;而且眼镜是我们日常生活中经常会使用的&…

介绍TCP/IP

TCP/IP&#xff08;传输控制协议/互联网协议&#xff09;是一种用于数据通信的基本通信协议&#xff0c;它是互联网的基础。TCP/IP指的是一组规则和过程&#xff0c;它规定了如何在网络上发送和接收数据。这个协议族由两个主要部分组成&#xff1a;传输控制协议&#xff08;TCP…

C#实现多种图片格式转换(例如转换成图标图像ICO)

1,目的: 实现多种图片格式的相互转换&#xff0c;图片大小可自定义等。 2&#xff0c;知识点: 转换成图标图像(ico)时&#xff0c;需要获取图像句柄&#xff0c;然后根据句柄生成Ico图像&#xff0c;否则生成的图像不能作为应用的图标使用。 IntPtr hwd bitmap.GetHicon();…

MongoDB之概述、命令

基础知识 是什么 概念 分布式文件存储数据库&#xff0c;提供高可用、可扩展、易部署的数据存储解决方案。 结构 BSON存储类型 类似JSON的一种二进制存储格式。相比于JSON&#xff0c;提供更丰富的类型支持。 优点是灵活&#xff0c;缺点是空间利用率不佳。 类型说明解释…

python爬虫demo——爬取历史平均房价

简单爬取历史房价 需求 爬取的网站汇聚数据的城市房价 https://fangjia.gotohui.com/ 功能 选择城市 https://fangjia.gotohui.com/fjdata-3 需要爬取年份的数据&#xff0c;等等 https://fangjia.gotohui.com/years/3/2018/ 使用bs4模块 使用bs4模块快速定义需要爬取的…

基于springboot+微信小程序+vue实现的校园二手商城项目源码

介绍 校园二手商城&#xff0c;架构&#xff1a;springboot微信小程序vue 软件架构 软件架构说明 系统截图 技术选型 技术版本说明Spring Boot2.1.6MVC核心框架Spring Security oauth22.1.5认证和授权框架MyBatis3.5.0ORM框架MyBatisPlus3.1.0基于mybatis&#xff0c;使用…

生成对抗网络

目录 1.GAN的网络组成 2.损失函数解释说明 2.1 BCEloss 2.2整体代码 1.GAN的网络组成 2.损失函数解释说明 2.1 BCEloss 损失函数 import torch from torch import autogradinput autograd.Variable(torch.tensor([[1.9072,1.1079,1.4906],[-0.6584,-0.0512,0.7608],[-0.0…

【嵌入式移植】5、U-Boot源码分析2—make nanopi_neo2_defconfig

U-Boot源码分析2—make nanopi_neo2_defconfig 1 概述2 nanopi_neo2_defconfig3 编译过程分析3.1 编译目标3.2 scripts_basic3.2.1 prefix src定义3.2.2 PHONY3.2.3 __build3.2.4 fixdep3.3 objscripts/kconfig 1 概述 上一章中&#xff0c;对Makefile相关源码进行了初步分析&…

Vue-cli脚手架将组件挂载到全局

局部引用组件,直接将组件引入,注册组件即可,这篇文章讲组件挂载到全局的方法! main.js文件 将组件引入main.js文件中,并且注册 使用方法 在需要的地方使用组件即可 BaoGit.Vue代码 <template><div><a href"https://gitee.com/ah-ah-bao"><img …

【机器学习】正则化

正则化是防止模型过拟合的方法&#xff0c;它通过对模型的权重进行约束来控制模型的复杂度。 正则化在损失函数中引入模型复杂度指标&#xff0c;利用给W加权值&#xff0c;弱化了数据的噪声&#xff0c;一般不正则化b。 loss(y^,y)&#xff1a;模型中所有参数的损失函数&…

PID校正

一、Introduction to PID Control PID控制是一种应用非常广泛的控制算法。小到控制一个元件的温度&#xff0c;大到控制无人机的飞行姿态和飞行速度等等&#xff0c;都可以使用PID控制。PID(proportion integration differentiation)其实就是指比例&#xff0c;积分&#xff0…
最新文章