excel如何冻结多列中,取多列数据中符合要求的数据到指定列的函数 S2取值条件: R2=0,S2=Q2 Q2=0,S2=P2 P2=0,S2=O2

Excel中的数据分析工具
《统计学》课程实验指导
【试验目的】
能够使学生在学习统计学原理课程时,掌握统计学中的计算过程,理论联系实际。由于Excel是目前办公软件中比较流行的软件,因此,本试验课以该软件为基础,实现它的统计计算功能。通过该试验课程的学习,使每个学生能够达到能够利用该软件的统计计算功能熟练地完成教材中有关例题、习题的计算,并通过案例的学习,培养学生一定的解决实际问题的能力。
【试验内容】
Excel中的统计分析功能,包括算术平均数、加权平均数、方差、标准差、协方差、相关系数、统计图形、随机抽样、参数点估计、区间估计、假设检验、方差分析、移动平均、指数平滑、回归分析。
【试验计划】
两个教学周,上试验课一次,时间一小时。
【试验地点】
学院办公楼二层计算机机房
描述性统计在Excel中的操作程序
此分析工具用于生成对输入区域中数据的单变值分析,提供有关数据趋中性和易变性的信息。
(-)“描述统计”对话框
在此输入待分析数据区域的单元格引用。该引用必须由两个或两个以上按列或行组织的相邻数据区域组成。
如果需要指出输入区域中的数据是按行还是按列排列,请单击“逐行”或“逐列”。
标志位于第一行/列
如果输入区域的第一行中包含标志项,请选中“标志位于第一行”复选框;如果输入区域的第一列中包含标志项,请选中“标志位于第一列”复选框;如果输入区域没有标志项,则该复选框不会被选中,Microsoft Excel 将在输出表中生成适宜的数据标志。
平均数置信度
如果需要在输出表的某一行中包含均值的置信度,请选中此复选框,然后在右侧的编辑框中,输入所要使用的置信度。例如,数值 95% 可用来计算在显著性水平为 5% 时的均值置信度。
如果需要在输出表的某一行中包含每个区域的数据的第 k 个最大值,请选中择此复选框,然后在右侧的编辑框中,输入 k 的数值。如果输入 1,则这一行将包含数据集中的最大数值。
如果需要在输出表的某一行中包含每个区域的数据的第 k 个最小值,请选中此复选框,然后在右侧的编辑框中,输入 k 的数值。如果输入 1,则这一行将包含数据集中的最小数值。
在此输入对输出表左上角单元格的引用。此工具将为每个数据集产生两列信息。左边一列包含统计标志项,右边一列包含统计值。根据所选择的“分组方式”选项的不同,Microsoft Excel 将为输入表中的每一行或每一列生成一个两列的统计表。
新工作表组
单击此选项,可在当前工作簿中插入新工作表,并由新工作表的 A1 单元格开始粘贴计算结果。如果需要给新工作表命名,请在右侧编辑框中键入名称。
单击此选项,可创建一新工作簿,并在新工作簿的新工作表中粘贴计算结果。
如果需要 Microsoft Excel 在输出表中生成下列统计结果,请选中此复选框。这些统计结果有:平均值、标准误差(相对于平均值)、中值、众数、标准偏差、方差、峰值、偏斜度、极差(全距)、最小值、最大值、总和、总个数、Largest (#)、Smallest (#) 和置信度。
(二)实例应用:
&&& 某老师对几名学生的五次考试成绩进行分析,以便对这几个学生在学习方面的问题加以解决。使用“描述统计”分析工具对其数据进行分析。(数据文件名:描述统计.xls)
操作步骤:
2、选择“数据分析”对话框中“描述统计”,跳出“描述统计”对话框。
&&& 在数据输出的工作表中,可以看出每个学生的的成绩的各种分析结果。其中第3行至第18行分别为:平均值、标准误差、中值、标准误差、样本方差、峰值、偏度、最大值、最小值、和、计数、第1大值、第1小值、95%概率保证程度的置信度。根据“标准偏差”值可以看出王华的成绩离散程度最大,即是说其成绩极不稳定,刘明的成绩是最稳定的。若取中值进行分析则是王华的成绩最好。平均值为刘明最佳。总体上而言,王华的成绩应该是最好的,只是最后一次的成绩太差,造成了较大的影响。
试验二:& 统计直方图在Excel中的操作程序
在给定工作表中数据单元格区域和接收区间的情况下,计算数据的个别和累积频率,用于统计有限集中某个数值元素的出现次数。例如,在一个有 20 名学生的班级里,可以确定以字母打分(如 A、B-等)所得分数的分布情况。直方图表会给出字母得分的边界,以及在最低边界与当前边界之间某一得分出现的次数。出现频率最多的某个得分即为数据组中的众数。
“直方图”对话框
接收区域(可选)
在此输入接收区域的单元格引用,该区域应包含一组可选的用来定义接收区间的边界值。这些值应当按升序排列。只要存在的话,Microsoft Excel 将统计在当前边界点和相邻的高值边界点之间的数据点个数。如果某个数值等于或小于某个边界值,则该值将被归到以该边界值为上限的区间中。所有小于第一个边界值的数值将一同计数,同样所有大于最后一个边界值的数值也将一同记数。
如果省略此处的接收区域,Microsoft Excel 将在数据组的最小值和最大值之间创建一组平滑分布的接收区间。
选中此复选框,可以在输出表中同时按降序排列频率数据。如果此复选框被清除,Microsoft
Excel 将只按升序来排列数据,即省略输出表中最右边的三列数据。
累积百分率
选中此复选框,可以在输出表中添加一列累积百分比数值,并同时在直方图表中添加累积百分比折线。如果清除此选项,则会省略累积百分比。
选中此复选框,可以在输出表中同时生成一个嵌入式直方图表。
实例应用:
&&& 学生历次考试成绩统计,按照一定区间生成频数分布表,使用“直方图”分析工具来完成。(数据文件名:直方图.xls)
操作步骤:
5、看是否在输入栏里是否选择了标志单元格,考虑选定“标志”。在输出选项中选择“新工作表组”,在其对应编辑框中输入输出工作表名称,如;“图表输出”。选择“帕拉图”、“累积百分率”、“图表输出”选项。
&&& 在图中显示的统计结果中,可以看见输出的内容分为两部分,一部分是数据表示形式,一部分是直方图形式。在数据表部分,显示每个区间中的人数及累计百分率数值。通过该统计结果,我们可以知道,在第一次考试中有6人在100~85分之间,5人在85~75之间,1人在75~65之间,1人在65以下。
试验三:& 协方差和相关系数在Excel中的计算
&& 1、协方差
此分析工具及其公式用于返回各数据点的一对均值偏差之间的乘积的平均值。协方差是测量两组数据相关性的量度。
可以使用协方差工具来确定两个区域中数据的变化是否相关,即,一个集合的较大数据是否与另一个集合的较大数据相对应(正协方差);或者一个集合的较小数据是否与另一个集合的较小数据相对应(负协方差);还是两个集合中的数据互不相关(协方差为零)。
&“协方差”对话框
在此输入待分析数据区域的单元格引用。该引用必须由两个或两个以上按列或行组织的相邻数据区域组成。
实例应用:
&&& 用协方差分析工具分析某公司历史“推销费用”、“销售额”、“营业人员”三项数据之间是否存在相关。(数据文件名:协方差.xls)
操作步骤:
1、打开数据“协方差.xls”,如下:
2、选择“数据分析”对话框中“协方差”,跳出“协方差”对话框。
3、在“输入区域”编辑框中键入三列数据所在的单元格区域引用($B$1:$D$9)。
&&& 在上图所示的输出表为“推销费用”、“营业员”、“销售额”三个变量的协方差矩阵。明显,对角线上为各自方差;其他,三个变量相互之间协方差分别为:202.125、199.5、610.5,说明三个变量之间存在较显著的相关性,不是相互独立的。
2、相关系数
此分析工具及其公式可用于判断两组数据集(可以使用不同的度量单位)之间的关系。总体相关性计算的返回值为两组数据集的协方差除以它们标准偏差的乘积:
&&& 根据图中所示工作表显示的计算结果数据,可一直到两个温度下产品的轻度不受影响(即可认为两种温度下强度祥等)。
(二)“t - 检验:双样本异方差假设”分析
此分析工具及其公式可以进行双样本学生氏 t –检验。此 t - 检验先假设两个数据集的方差不等,故也称作异方差 t - 检验。可以使用 t - 检验来确定两个样本均值实际上是否相等。当进行分析的样本组不同时,可使用此检验。如果某一样本组在某次处理前后都进行了检验,则应使用“成对检验”。
用于确定检验统计值 t 的公式如下:
下面的公式用于估计自由度。因为计算结果通常不为整数,从 t 分布表中查找临界值时,应使用最接近的整数。
“t - 检验:双样本异方差假设”对话框
&&& 根据图中所示工作表显示的计算结果数据,原假设不成立,可以知道两个温度下产品的强度不受影响(即可认为两种温度下强度相等)。
(三)t - 检验:平均值的成对二样本分析
此分析工具及其公式可以进行成对双样本学生氏 t - 检验,用来确定样本均值是否不等。此 t -检验并不假设两个总体的方差是相等的。当样本中出现自然配对的观察值时,可以使用此成对检验,例如对一个样本组进行了两次检验,抽取实验前的一次和实验后的一次。
注意&& 由此工具生成的结果中包含有合并方差,亦即数据相对于平均数据离散值的累积测量值,可以由下面的公式得到:
“t - 检验:平均值的成对二样本分析”对话框
试验五:& z统计检验在Excel中的操作程序
此分析工具可以进行方差已知的双样本均值 z - 检验。此工具用于检验两个总体均值之间存在差异的假设。例如,可以使用此检验来确定两种汽车模型性能之间的差异情况。
“z - 检验:双样本平均差检验”对话框
&&& 可以看到Z值为-1.61245,双尾临界值为1.959961,因此,可以接受零假设,认为两地水源矿物质含量无显著差异。
试验六:& F统计检验在Excel中的操作程序
此分析工具可以进行双样本
F - 检验,用来比较两个样本总体的方差。例如,可以对参加游泳比赛的两个队的时间记分进行 F- 检验,查看二者的样本方差是否不同。
“F - 检验:双样本方差分析”对话框
变量 1 的区域
在此输入对需要分析的第一列或第一行数据的引用。
变量 2 的区域
在此输入对需要分析的第二列或第二行数据的引用。
在此输入检验的置信度。该值必须在范围
0~1 之间。Alpha 置信度为 I 型错误发生概率的显著性水平(舍弃真实假设)。
实例应用:
&&& 对测试产品在不同温度下强度的实验数据进行“F - 检验双样本方差分析”,以检查两种数据下测得的数据方差是不是相等。(数据文件名:F
- 检验:双样本方差分析.xls)
操作步骤:
试验七:& 方差分析 (anova)在Excel中的操作程序
“分析工具库”中提供了三种工具,可用来分析方差。具体使用哪一工具则根据因素的个数以及待检验样本总体中所含样本的个数而定。
(一)“Anova:单因素方差”分析
此分析工具通过简单的方差分析(anova),对两个以上样本均值进行相等性假设检验(抽样取自具有相同均值的样本空间)。此方法是对双均值检验(如 t-检验)的扩充。
“Anova:单因素方差分析”对话框
在此输入待分析数据区域的单元格引用。该引用必须由两个或两个以上按列或行组织的相邻数据区域组成。
在此输入计算 F 统计临界值的置信度。Alpha
置信度为 I 型错误发生概率的显著性水平(舍弃真实假设)。
实例应用:
&&& 检验某市职工工资总额与商品零售总额是否存在线性关系(数据文件名:单因素方差分析.xls)。
操作步骤:
1、打开数据“单因素方差分析.xls”,如下:
2、选择“数据分析”对话框中“单因素方差分析”,跳出“单因素方差分析”对话框。
3、在“输入区域”编辑框中键入三列数据所在的单元格区域引用($B$1:$C$11)。
通过图中显示数据,用户可以看到F值远大于“Fcrit”得知,因此零假设不被接受,说明年度职工工资总额对当前社会商品零售总额是显著的线性相关。
(二)“Anova:可重复双因素”分析
此分析工具是对单因素 anova 分析的扩展,即每一组数据包含不止一个样本。
“Anova:可重复双因素分析”对话框
在此输入待分析数据区域的单元格引用。该引用必须由两个或两个以上按列或行组织的相邻数据区域组成。
每一样本的行数
在此输入包含在每个样本中的行数。每个样本必须包含同样的行数,因为每一行代表数据的一个副本。
在此输入需要用来计算 F 统计的临界值的置信度。Alpha 置信度为 I 型错误发生概率的显著性水平(舍弃真实假设)。
实例应用:
&&& 测试产品不同温度下的强度,将原来8次测试值改为每次试验得到4个测试值,而实验进行了2次。对两次试验得到的数据进行样本均值相等的假设检验。
操作步骤:
1、打开数据“双因素方差分析.xls”,选择“可重复双因素方差分析数据”工作表,如下:
2、选择“数据分析”对话框中“可重复双因素方差分析”,跳出“可重复双因素方差分析”对话框。
3、在“输入区域”编辑框中键入三列数据所在的单元格区域引用($A$1:$C$9)。
4、在“每一样本的行数”对应编辑框中填入4。
5、在“输出选项”下单击“新工作表组”选项,并在对应编辑框中输入新工作表的名称。如:“方差分析结果”。
&&& 在山图所示结果中给出了3个F值,分别用于不同样本之间的均值相等性假设检验。如果只是进行不同温度下的两组数据之间的均值相等性假设检验,则可以取“列”所对应的F值,并于同一行中所对应的“Fcrit”值进行比较,从而可以判断出该两组数据的均值相等性假设成立。
(三)“Anova:无重复双因素”分析
此分析工具通过双因素 anova 分析(但每组数据只包含一个样本),对两个以上样本均值进行相等性假设检验(抽样取自具有相同均值的样本空间)。此方法是对双均值检验(如 t-检验)的扩充。
“Anova:无重复双因素分析”对话框
在此输入待分析数据区域的单元格引用。该引用必须由两个或两个以上按列或行组织的相邻数据区域组成。
如果在输入区域中没有标志项,则本复选框不会被选中,Microsoft Excel 将在输出表中生成适宜的数据标志。
在此输入需要用来计算 F 统计的临界值的置信度。Alpha 置信度为 I 型错误发生概率的显著性水平(舍弃真实假设)。
实例应用:
&& 无重复双因素方差分析在使用时,不需人为将样本数据进行划分,而是自动将样本数据按照其所在的行为分为多个样本进行分析,这是和可重复双因素分析的区别所在。
&&& 采用无重复双因素方差分析与可重复双因素方差分析操作上差不多,将上例采用无重复双因素方差分析得出结果如下:
&&& 通过上图所示数据结果,可以看到他对给定样本的每一行都计算了平均值及方差,并根据特定的计算方法求得F值。虽然他求得的F值与其他两种分析工具求得的值不同,但三种方差分析工具的根本使用思想是一致的,将最终结果中“列”所对应的F值与“Fcrit”相比较,可以判断出样本均值相等性假设可以成立。
试验八:& 长期变动趋势在Excel中的操作程序
1、移动平均
此分析工具及其公式可以基于特定的过去某段时期中变量的均值,对未来值进行预测。预测值的计算公式如下:
在此输入待分析数据区域的单元格引用。该区域必须由包含四个以上数据单元格的单列组成。
在此输入用来进行移动平均计算的间隔数。默认间隔为 3。
在此输入对输出表左上角单元格的引用。如果选中了“标准误差”复选框,Microsoft Excel 将生成一个两列的输出表,其中右边的一列为标准误差值。如果没有足够的历史数据来进行预测或计算标准误差值,Microsoft Excel 会在某些单元格中返回错误值 #N/A。
此分析工具的输出区域必须与输入区域在同一工作表中。因此,“新工作表组”和“新工作簿”选项均不可使用。
选择此悬想可以在输出表中生成一个嵌入直方图。
如果要在输出表的一列中包含标准误差值,请选中此复选框;如果只需要没有标准误差值的单列输出表,请清除此复选框。
实例应用:
&&& 对公司11个月的销售数据采用移动平均法进行预测12月份的销售。(数据文件:移动平均.xls)
操作步骤:
注意& &0.2 到 0.3 之间的数值可作为合理的平滑常数。这些数值表明本次预测需要将前期预测值的误差调整 20% 到 30%。大一些的常数导致快一些的响应但会生成不可靠的预测。小一些的常数会导致预测值长期的延迟。
“指数平滑”对话框
在此输入待分析数据区域的单元格引用。该区域必须为包含四个以上单元格的单一行或列。
在此输入需要用作平滑常数的阻尼系数。阻尼系数是用来将总体中数据的不稳定性最小化的修正因子。默认的阻尼系数为 0.3。
选中此复选框可根据输出表中的实际数值和预测数值生成嵌入式图表。
实例应用:
&&& 对一系列数据的一次指数平滑预测。(数据文件名:指数平滑.xls)
操作步骤:
&&& 从上图可以看出,“阻尼系数”值为0.2的时候预测误差最小,因此,第13期的预测值为0.8×14+0.2×16.8=14.56。
&&& 从上面的图可以看出,以指数平滑预测的结果存在滞后偏差,即当时间序列呈下降趋势时,预测值往往偏高;反之,则偏低。另外,一次指数平滑预测只能做下一期的预测。
3、回归分析
此工具通过对一组观察值使用“最小二乘法”直线拟合,进行线形回归分析。本工具可用来分析单个因变量是如何受一个或几个自变量影响的。例如,观察某个运动员的运动成绩与一系列统计因素的关系,如年龄、身高和体重等。在操作时,可以基于一组已知的体能统计数据,并辅以适当加权,对尚未进行过测试的运动员的表现作出预测。
“回归分析”对话框
2、选择“数据分析”的“回归”,跳出“回归”对话框。
3、在“Y值输入区域”编辑框中键入销售额列单元格的引用。
4、在“X值输入区域”编辑框中键入推销费用、营业人员列单元的的引用。
5、在“输出选项”区域中单击“新工作表组”选项,在对应编辑框键入新工作表名称,如“回归分析结果”。
6、单击确定,输出数据如下
7、在“数据”工作表中C12单元格输入公式“=回归分析结果!B17+回归分析结果!B18*200+回归分析结果!B19*310”。
&&& 最后得出,2002年销售额预计为310.8314万元。C++primer第14章习题解答
练习14.1:在什么情况下重载的运算符与内置运算符有所区别?在什么情况下重载的运算符又与内置运算符一样?
重载运算符必须具有至少一个class或枚举类型的操作数。
重载运算符不保证操作数的求值顺序,例如对&&和||的重载版本不再具有&短路求值&的特性,两个操作数都要求值,而且不规定操作数的求值顺序。
对于优先级和结合性级操作数的数目都不变。
练习14.2:为Sales_data编写重载的输入、输出、加法和复合赋值运算符的声明。
class Sales_data
friend std::istream& operator&&(std::istream&, Sales_data &);
friend std::ostream& operator&&(std::ostream&, const Sales_data&);
Sales_data& operator+=(const Sales_data&);
Sales_data operator+(const Sales_data&, const Sales_data&);
练习14.3:string和vector都定义了重载的==以比较各自的对象,假设svec1和svec2是存放string的vector,确定在下面的表达式中分别使用了哪个版本的==?
(a) &cobble& == &stone& (b) svec1[0] ==svec2[0] (c)svec1 ==svec2 (d) svec[0] == &stone&
(a)应用了C++内置版本的==,比较两个指针。(b) 应用了string版本的==。(c)应用了vector版本的==。(d)应用了string版本的==。
练习14.4:如何确定下列运算符是否应该是类的成员?
(a) % (b) %= (c) ++ (d) -& (e) && (f) && (g) == (h) ()
(a) %通常定义为非成员。
(b) %=通常定义为类成员,因为它会改变对象的状态。
(c) ++通常定义为类成员,因为它会改变对象的状态。
(d) -&必须定义为类成员,否则编译报错
(e) &&通常定义为非成员
(f) && 通常定义为非成员。
(g) ==通常定义为非成员。
(h) ()必须定义为类成员,否则编译会报错。
练习14.5:在7.5.1节的练习7.40中,编写了下列类中的某一个框架,请问在这个类中应该定义重载的运算符吗?如果是,请写出来。
(a)Book (b)Date (c)Employee (d)Vehicle (e)Object (f)Tree
using std::
using std::
class Date
Date() { }
Date(int y, int m, int d) {year = month = day =}
friend ostream& operator&&(ostream &os, const Date &dt);
int year, month,
ostream& operator&&(ostream& os, const Date& d)
const char sep = '\t';
os && &year:& && d.year && sep && &month:& && d.month && sep && &day:& && d.day &&
练习14.6:为你的Sales_data类定义输出运算符。
class Sales_data
friend ostream& operator&&(ostream &os, const Sales_data &item);
//其他成员
ostream& operator&&(ostream &os, const Sales_data &item)
const char *sep = ' ';
os && item.isbn() && sep && item.units_sold && sep && item.revenue &&
练习14.7:你在13.5节的练习中曾经编写了一个String类,为它定义一个输出运算符。
class String
String(const char *str);
friend ostream& operator&&(ostream &os, const String &str);
ostream& operator&&(ostream &os, const String &str)
练习14.8:你在7.51节的练习7.40中曾经选择并编写了一个类,为它定义一个输出运算符。
见练习14.5。
练习14.10:对于Sales_data的输入运算符来说如果给定了下面的输入将发生什么情况?
(a)0-201- 24.95 (b) 10 24.95 0-210-99999-9
(a)参数中传入的Sales_data对象将会得到输入的值,其中bookNo、units_sold、price的值分别是0-201-、24.95,同时revenue的值是249.5.
(b)输入错误,参数中传入的Sales_data对象将会得到默认值。
练习14.11:下面的Sales_data输入运算符存在错误吗?如果有,请指出来。对于这个输入运算符如果仍然给定上一个练习的输入将发生什么情况?
istream& operator&&(istream& in, Sales_data& s)
in && s.bookNo && s.unite_sold &&
s.revenue = s.unite_sold *
这个实现没有判断输入数据的正确性,是错误的。
(a)如果输入的是0-201- 24.95,程序不会报错,Sales_data能得到正确的值。
(b)如果输入的是10 24.95 0-201-99999-9,Sales_data会得到错误的值。
练习14.12:你在7.5.1节的练习中曾经选择并编写了一个类,为它定义一个输入运算符并确保该运算符可以处理输入错误。
using std:: class Date { public: Date() { } Date(int y, int m, int d) {year = month = day =} friend istream& operator&&(istream &is, Date &dt); private: int year, month, }; istream& operator&&(istream &is, Date &dt) { is && dt.year && dt.month && dt. if (!is) dt = Date(0, 0, 0); }
练习14.13:你认为Sales_data类还应该支持 哪些其他算术运算符?如果有的话,请给出它们的定义。
可以定义一个减法运算符
class Sales_data
friend Sales_data operator-(const Sales_data &lhs, const Sales_data &rhs);
Sales_data& operator-=(const Sales_data &rhs);
//其他成员
Sales_data operator-(const Sales_data &lhs, const Sales_data &rhs)
Sales_data sub =
Sales_data& Sales_data::operator-=(const Sales_data &rhs)
units_sold -= rhs.units_
revenue -= rhs.
练习14.14:你觉得为什么调用operator+=来定义operator+比其他方法要更有效?
从头实现operator+的方式与借助operator+=实现的方式相比,在性能上没有优势,而可读性上后者显然更好。
练习14.15:你在7.5.1节的练习7.40中曾经选择并编写了一个类。你认为它应该含有其他算术运算符吗?如果是,请实现它们;如果不是,解释原因。
在练习7.40中,变写了Date类,算术运算对Date没有太大意义,不需要为Date重载算术运算符。
练习14.16:为你的StrBlob类、StrBlobPtr类、StrVec类和String类分别定义相等和不相等运算符。
class StrBlob
friend bool operator==(const StrBlob &lhs, const StrBlob &rhs);
friend bool operator!=(const StrBlob &lhs, const StrBlob &rhs);
//其他成员
bool operator==(const StrBlob &lhs, const StrBlob &rhs)
return lhs.data ==rhs.
bool operator!=(const StrBlob &lhs, const StrBlob &rhs)
return !(lhs == rhs);
//StrBlobPtr
class StrBlobPtr
friend bool operator==(const StrBlobPtr &lhs, const StrBlobPtr &rhs);
friend bool operator!=(const StrBlobPtr &lhs, const StrBlobPtr &rhs);
//其他成员
bool operator==(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
auto l = lhs.wptr.lock(), r = rhs.wptr.loc();
if (l == r)
return (!r || lhs.curr == rhs.curr);
bool operator!=(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
return !(lhs == rhs);
class StrVec
friend bool operator==(const StrVec &lhs, const StrVec &rhs);
friend bool operator!=(const StrVec &lhs, const StrVec &rhs);
//其他成员
bool operator==(const StrVec &lhs, const StrVec &rhs)
if (lhs.size() == rhs.size())
for (auto itr1 = lhs.begin(), itr2 = rhs.begin(); itr1 != lhs.end() && itr2 != rhs.end(); ++itr1, ++itr2)
if (*itr1 != *itr2)
bool operator!=(const StrVec &lhs, const StrVec &rhs)
return !(lhs == rhs);
class String
friend bool operator==(const String &lhs, const String &rhs);
friend bool operator!=(const String &lhs, const String &rhs);
//其他成员
const char *
bool operator==(const String &lhs, const String &rhs)
return strcmp(lhs.str, rhs.str);
bool operator!=(const String &lhs, const String &rhs)
return !(lhs == rhs);
练习14.17:你在7.5.1节的练习7.40中曾经选择并编写了一个类,你认为它应该含有相等运算符吗?如果是,请实现它;如果不是,解释原因。
class Date
friend bool operator==(const Date &dl, const Date &d2);
friend bool operator!=(const Date &d1, const Date &d2);
//其他成员
bool operator==(const Date &d1, const Date &d2)
return d1.year == d2.year && d1.month == d2.month && d1.day == d2.
bool operator!=(const Date &d1, const Date &d2)
return !(da == d2);
14.18:为你的StrBlob类、StrBlobPtr类、StrVec类、String类定义关系运算符。
class String
friend bool operator&(const String &s1, const String &s2);
friend bool operator&=(const String &s1, const String &s2);
friend bool operator&(const String &s1, const String &s2);
friend bool operator&=(const String &s1, const String &s2);
//其他成员
friend bool operator&(const String &s1, const String &s2)
return strcmp(s1.str, s2.str) & 0;
friend bool operator&=(const String &s1, const String &s2)
return strcmp(s1.str, s2.str) &= 0;
friend bool operator&(const String &s1, const String &s2)
return strcmp(s1.str, s2.str) & 0;
friend bool operator&=(const String &s1, const String &s2)
return strcmp(s1.str, s2.str) &= 0;
class StrBlob
friend bool operator&(const StrBlob &s1, const StrBlob &s2);
friend bool operator&=(const StrBlob &s1, const StrBlob &s2);
friend bool operator&(const StrBlob &s1, const StrBlob &s2);
friend bool operator&=(const StrBlob &s1, const StrBlob &s2);
bool operator&(const StrBlob &s1, const StrBlob &s2)
return *s1.data & *s2.
bool operator&=(const StrBlob &s1, const StrBlob &s2)
return *s1.data &= *s2.
bool operator&(const StrBlob &s1, const StrBlob &s2)
return *s1.data & *s2.
bool operator&=(const StrBlob &s1, const StrBlob &s2)
return *s1.data &= *s2.
class StrBlobPtr
friend operator&(const StrBlobPtr &s1, const StrBlobPtr &s2);
friend operator&=(const StrBlobPtr &s1, const StrBlobPtr &s2);
friend operator&(const StrBlobPtr &s1, const StrBlobPtr &s2);
friend operator&=(const StrBlobPtr &s1, const StrBlobPtr &s2);
bool operator&(const StrBlobPtr &s1, const StrBlobPtr &s2)
auto l = s1.wptr.lock(), r = s2.wptr.lock();
if (l == r)
return (s1.curr & s2.curr);
bool operator&=(const StrBlobPtr &s1, const StrBlobPtr &s2)
auto l = s1.wptr.lock(), r = s2.wptr.lock();
if (l == r)
return (!r || s1.curr &= s2.curr);
bool operator&(const StrBlobPtr &s1, const StrBlobPtr &s2)
auto l = s1.wptr.lock(), r = s2.wptr.lock();
if (l == r)
return (s1.curr & s2.curr);
bool operator&=(const StrBlobPtr &s1, const StrBlobPtr &s2)
auto l = s1.wptr.lock(), r = s2.wptr.lock();
if (l == r)
return (!r || s1.curr &= s2.curr);
class StrVec
friend operator&(const StrVec &s1, const StrVec &s2);
friend operator&=(const StrVec &s1, const StrVec &s2);
friend operator&(const StrVec &s1, const StrVec &s2);
friend operator&=(const StrVec &s1, const StrVec &s2);
//其他成员
bool operator&(const StrVec &s1, const StrVec &s2)
for (auto p1 = s1.begin(), p2 = s2.begin(); p1 != s1.end(), p2 != s2.end(); ++p1, ++p2)
if (*p1 & *p2)
else if (*p1 & *p2)
if (p1 == s1.end() && p2 != s2.end())
bool operator&=(const StrVec &s1, const StrVec &s2)
for (auto p1 = s1.begin(), p2 = s2.begin(); p1 != s1.end(), p2 != s2.end(); ++p1, ++p2)
if (*p1 & *p2)
else if (*p1 & *p2)
if (p1 == s1.end())
bool operator&(const StrVec &s1, const StrVec &s2)
for (auto p1 = s1.begin(), p2 = s2.begin(); p1 != s1.end(), p2 != s2.end(); ++p1, ++p2)
if (*p1 & *p2)
else if (*p1 & *p2)
if (p1 == s1.end() && p2 != s2.end())
bool operator&=(const StrVec &s1, const StrVec &s2)
for (auto p1 = s1.begin(), p2 = s2.begin(); p1 != s1.end(), p2 != s2.end(); ++p1, ++p2)
if (*p1 & *p2)
else if (*p1 & *p2)
if (p2 == s2.end())
练习14.19:你在7.5.1节的练习7.40中曾经选择并编写了一个类,你认为它应该含有关系运算符吗?如果是,请实现它;如果不是,解释原因。
class Date
friend operator&(const Date &d1, const Date &d2);
friend operator&=(const Date &d1, const Date &d2);
friend operator&(const Date &d1, const Date &d2);
friend operator&=(const Date &d1, const Date &d2);
//其他成员
bool operator&(const Date &d1, const Date &s2)
return (d1.year & d2.year) || (d1.year == d2. year && d1.month & d2.month) || (d1.year == d2.year && d1.month == d2.month && d1.day & d2.day);
bool operator&=(const Date &d1, const Date &s2)
return (d1 & d2) || (d1 == d2);
bool operator&(const Date &d1, const Date &s2)
return !(d1 &= d2);
bool operator&=(const Date &d1, const Date &s2)
return (d1 & d2) || (d1 == d2);
练习14.20:为你的Sales_data类实现加法和复合赋值运算符。
class Sales_data
friend Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs);
Sales_data& operator+=(const Sales_data &rhs);
//其他成员
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
Sales_data sum =
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
units_sold += rhs.units_
revenue += rhs.
练习14.21:编写Sales_data类的+和+=运算符,是的+执行实际的加法操作,而+=调用+。相比于14.3节和14.4节对这两个运算符的定义,本题的定义有何缺点?试讨论之。
在性能上没有优势,可读性也不好。
class Sales_data
friend Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs);
Sales_data& operator+=(const Sales_data &rhs);
//其他成员
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
Sales_data sum =
units_sold += rhs.units_
revenue += rhs.
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
*this = (*this) +
练习14.22:定义赋值运算符的一个新版本,使得我们能把一个表示ISBN的string赋给一个Sales_data对象。
class Sales_data
Sales_data& operator=(const string &isbn);
//其他成员
Sales_data& Sales_data::operator=(const string &isbn)
练习14.23:为你的StrVec类定义一个initializer_list赋值运算符。
class StrVec
StrVec& operator=(std::initializer_list il);
//其他成员
StrVec& StrVec::operator=(std::initializer_list il)
auto data = alloc_n_copy(il.begin(), il.end());
elements = data.
first_free = cap = data.
练习14.24:你在7.5.1节的脸7.40中曾经选择并编写了一个类,你认为它应该含有拷贝赋值和移动赋值运算符吗?如果是,请实现它们。
再联系7.40中,我们变细了Date类,它只有三个int类型的数据成员,浅拷贝就能满足要求,因此不需要另外定义拷贝赋值和移动赋值运算符。
练习14.25:上题的这个类还需要定义其他赋值运算符吗?如果是,请实现它们;同时说明运算对象应该是什么类型并解释原因。
class Date
Date& operator=(const string &date);
//其他成员
Date& Sales_data::operator=(const string &date)
istringstream in(date);
char ch1, cha2;
in && year && ch1 && month && ch2 &&
if (!in || ch1 != '-' || ch2 != '-')
throw std::invalid_argument(&Bad date&);
if (month & 1 || month &12 || day & 1 || day & 31)
throw std::invalid_argument(&Bad date&);
练习14.26:为你的StrBlob类、StrBlobPtr类,StrVec类和String类定义下标运算符。
class StrBlob
std:;string& operator[](std:;size_t n) { return data[n]; }
const std:;string& operator[](std:;size_t n) const { return data[n]; }
class StrBlobPtr
std::string& operator[](std::size_t n) { return (*wptr.lock())[n]; }
const std::string& operator[](std::size_t n) const { return (*wptr.lock())[n]; }
class StrVec
std:;string& operator[])(std:;size_t n) { return elements[n]; }
const std:;string& operator[])(std:;size_t n) const { return elements[n]; }
class String
char& operator[](std::size_t n) { return (char) str[n]; }
const char& operator[](std::size_t n) const { return (char) str[n]; }
练习14.27:为你的StrBlobPtr类添加递增和递减运算符。
class StrBlobPtr
StrBlobPtr& operator++();
StrBlobPtr& operator--();
StrBlobPtr operator++(int);
StrBlobPtr operator--(int);
StrBlobPtr& StrBlobPtr::operator++()
check(curr, & increment past end of StrBlobPtr &);
StrBlobPtr& StrBlobPtr::operator--()
check(-1, & decrement past begin of StrBlobPtr &);
StrBlobPtr StrBlobPtr::operator++(int)
StrBlobPtr ret = *
StrBlobPtr StrBlobPtr::operator--(int)
StrBlobPtr ret = *
练习14.28:为你的StrBlobPtr类添加加法和减法运算符,使其可以实现指针的算术运算。
class StrBlobPtr
friend StrBlobPtr operator+(int n);
friend StrBlobPtr operator-(int n);
//其他成员
StrBlobPtr StrBlobPtr::operator+(int n)
auto ret = *
ret.curr +=
StrBlobPtr StrBlobPtr::operator-(int n)
auto ret = *
ret.curr -=
练习14.29:为什么不定义const版本的递增和递减运算符?
对于++和--运算符,无论他是前缀版本还是后缀版本,都会改变对象本身的值,因此不能定义成const的。
练习14.30:为你的StrBlob类和在12.1.6节练习12.22中定义的ConstStrBlobPtr类分别添加解引用运算符和箭头运算符。注意:因为ConstStrBlobPtr的数据成员指向const vector,所以ConstStrBlobPtr中的运算符必须返回常量引用。
class StrBlobPtr
std::string& operator*() const
auto p = check(curr, &dereference past end&);
return (*p)[curr];
std::string* operator-&() const
return &(this-&operator*());
class ConstStrBlobPtr
const std::string& operator*() const
auto p = check(curr, &dereference past end&);
return (*p)[curr];
const std::string* operator-&() const
return &(this-&operator*());
练习14.31:我们的StrBlobPtr类没有定义拷贝构造函数、赋值运算符和析构函数,为什么?
对于StrBlobPtr类,它的数据成员有两个,分别是weak_ptr<vector&和size_t类型的,前者定义了自己的拷贝构造函数、赋值运算符和析构函数,后者是内置类型,因此默认的拷贝语义即可,无须为StrBlobPtr定义拷贝构造函数、赋值运算符和析构函数。</vector
练习14.32:定义一个类令其含有指向StrBlobPtr对象的指针,为这个类定义重载的建投运算符。
class MyClass
std::string* operator-&() const
return ptr-&operator-&();
StrBlobPtr *
练习14.33:一个重载的函数调用运算符应该接受几个运算对象?
0个或多个。
练习14.34:定义一个函数对象类,伶气质型if-then-else的操作:该类的调用运算符接受三个形参,它首先检查第一个形参,如果成功返回第二个形参的值,如果不成功返回第三个形参的值。
class IfElseThen
IfElseThen() { }
IfElseThen(int i1, int i2, int i3) : iVal1(i1), iVal2(i2), iVal3(i3) { }
int operator()(int i1, int i2, int i3)
return i1 ? i2 : i3;
int iVal1, iVal2, iVal3;
练习14.35:编写一个类似PrintString的类,令其从istream中读取一行输入,然后返回一个表示我们所读内容的string。如果读取失败,返回空string。
class ReadString
ReadString(istream &is = cin) : is(is) { }
std:;string operator()()
if (!getline(is, line))
line = & &;
练习14.36:使用前一个练习定义的类读取标准输入,将每一行保存为vector的一个元素。
void testReadString()
while (true)
string line = rs();
if (!line.empty())
vec.push_back(line);
练习14.37:编写一个类令其检查两个值是否相等。使用该对象及标准库算法编写程序,令其替换某个序列中具有给定值的所有实例。
class IntCompare
IntCompare(int v) : val(v) { }
bool operator()(int v) { return val ==v; }
int main()
vector vec = {1, 2, 3, 2, 1};
const int oldValue = 2;
const int newValue = 200;
IntCompare icmp(oldValue);
std::replace_if(vec.begin(), vec.end(), icmp, newValue);
练习14.38:编写一个类令其检查某个给定的string对象的长度是否与一个阀值相等。使用该对象编写程序,统计并报告在输入的文件中长度为1的单词有多少个、长度为2的单词有多少个。
using std::
using std::
using std::
using std::
using std::
using std::
class StrLenIs
StrLenIs(int len) : len(len) { }
bool operator()(const string &str) { return str.length() == }
void readStr(istream &is, vector &vec)
while (is && word)
vec.push_back(word);
int main()
readStr(cin, vec);
const int minLen = 1;
const int maxLen = 10;
for (int i = minL i &= maxL ++i)
StrLenIs slenIs(i);
cout && &len: & && i && &, cnt: & && count_if(vec.begin(), vec.end(), slenIs) &&
练习14.39:修改上一题的程序令其报告长度在1至9之间的单词有多少个、长度在10以上的单词又有多少个。
using std::
using std::
using std::
using std::
using std::
using std::
class StrLenBetween
StrLenBetween(int minLen, int maxLen) : minLen(minLen), maxLen(maxLen) { }
bool operator()(const string &str) { return str.length() &= minLen && str.length() &= maxL }
int minLen, maxL
class StrNoShorterThan
StrNoShorterThan(int len) : minLen(len) { }
bool operator()(const string &str) { return str.length() &= minL }
void readStr(istream &is, vector &vec)
while (is && word)
vec.push_back(word);
int main()
readStr(cin, vec);
StrLenBetween slenBetween(1, 9);
StrNoShorterThan sNoShorterThan(10);
cout && &len 1-9 :& && count_if(vec.begin(), vec.end(), slenBetween) &&
cout && &len &= 10 : & && count_if(vec.begin(), vec.end(), sNoShorterThan) &&
练习14.40:重新编写10.3.2节的biggies函数,使用函数对象替换其中的lambda表达式。
class IsShorter
bool operator()(const string &s1, const string &s2)
return s1.size() & s2.size();
class NotShorterThan
NotShorterThan(int len) : minLen(len) { }
bool operator()(const string &str)
return str.size() &= minL
class PrintString
void operator()(const string &str)
cout && str && & &;
void biggies(vector &words, vector::size_type sz)
elimDups(words);
stable_sort(words.begin(), words.end(), is);
NotShorterThan nst(sz);
auto wc = find_if(words.begin(), words.end(), nst);
auto count = words.end() -
cout && count && & & && make_plural(count, &words&, &s&) && & of length & &, sz && & or longer& &&
练习14.41:你认为C++11新标准为什么要增加lambda?对于你自己来说,什么情况下会使用lambda,什么情况下会使用类?&在C++11中,lambda是通过匿名的函数对象来实现的,因此我们可以把lambda看作是对函数对象在使用方式上进行的简化。当代码需要一个简单的函数,并且这个函数并不会在其他地方被使用时,就可以使用lambda来实现,此时它所起的作用类似于匿名函数。但如果这个函数需要多次使用,并且它需要保存某些状态的话,使用函数对象更合适一些。&练习14.42:使用标准库函数对象及适配器定义一条表达式,令其(a)统计大于1024的值有多少个。(b)找到第一个不等于pooh的字符串。(c)将所有的值乘以2.&count_if(vec.begin(), vec.end(), bind2nd(greater(), 1024));
find_if(vec.begin(), vec.end(), bind2nd(not_equal_to(), &pooh&));
transform(vec.begin(), vec.end(), vec.begin(), bind2nd(multiplies(), 2));
练习14.43:使用标准库函数对象判断一个给定的int值是否能被int容器中的所有元素整除。
bool divideByAll(vector &ivec, int dividend)
return count_if(ivec.begin(), ivec.end(), bindlst(modulus, dividend)) == 0;
练习14.44:编写一个简单的桌面计算器使其能处理二元运算。
using std::
using std::
using std::
using std::
using std::
using std::
using std::
using std::
using std::
using std::
using std::
map& binOps ={
{&+&, plus()},
{&-&, minus()},
{&*&, multiplies()},
{&/&, divides()},
{&%&, modulus()}
int main()
cin && a && op &&
cout&& binOps[op](a, b) &&
练习14.45:编写类型转换运算符将一个Sales_data对象分别转换成string和double,你认为这些运算符的返回值应该是什么?
如果要转换成string,那么返回值应该是bookNo。
如果要转换成double,那么返回值应该是revenue。
练习14.46:你认为应该为Sales_data类定义上面两种类型转换运算符吗?应该把它们声明成explicit的吗?为什么?
Sales_data不应该定义这两种类型转换运算符,因为对于类来说,它包含三个数据成员:bookNo,units_sold和revenue,只有三者在一起才是有效的数据。但是如果确实想要定义这两个类型转换运算符的话,应该把它们声明成explicit的,这样可以防止sales_data 在默写情况下被默认转换成string或double类型,这有可能导致意料之外的运算结果。
练习14.47:说明下面这两个类型转换运算符的区别。
struct Integral
operator const int();
operator int()
前者将对象转换成const int,在接受const int值的地方才能够使用。
后者将对象转换成int值,相对来说更加通用一些。
练习14.48:你在7.5.1节的练习7.40中曾经选择并编写了一个类,你认为它应该含有bool的类型转换运算符吗?如果是,解释原因并说明该运算符是否应该是explicit的;如果不是,也请解释原因。
之前我们编写了Date类,它含有3个数据成员:year、month和day。
我们可以为Date提供一个bool类型的转换运算符,用来检查3个数据成员是否都是有效值,bool类型转换运算符应该声明为explicit的,因为我们是有意要在条件表达式中使用它的。
练习14.49:为上一题提到的类定义一个转换目标是bool的类型转换运算符,先不用在意这么做是否应该。
class Date
explicit operator bool()
vector<vector& days_per_month = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
return 1 &= month && month &= 12 && 1 &= day && day &= days_per_month[isLeapYear()? 1 : 0][month - 1];
bool isLeapYear()
return (year % 4 ==0 && year % 100 != 0) || (year % 400 == 0);
};</vector
练习14.50:在初始化ex1和ex2的过程中,可能用到哪些类类型的转换序列呢?说明初始化是否正确并解释原因。
struct LongDouble {
LongDouble(double = 0.0);
operator double();
operator float();
LongDouble ldO
int ex1 = ldO
float ex2 ldO
对于int ex1 = ldOb;,它需要把LongDouble类型转换成int类型,但是LongDouble并没有定义对应的类型转换运算符,因此它会尝试使用其他的来进行转换。题中给出的两个都满足需求,但编译器无法确定那一个更合适,因此会产生二义性错误。
对于foloat ex2 = ldO,它需要把LongDouble转换成float类型,而我们恰好定义了对应的类型转换运算符,因此直接调用operator float()即可。
练习14.51:在调用calc的过程中,可能用到哪些类型转换序列呢?说明最佳可行函数是如何选拔出来的。
void calc(int);
void calc(LongDouble);
calc(dval);
这里会优先调用void calc(int)函数。因为double转换为int是标准类型转换,而转换为LongDouble则是转换为用户自定义类型,实际上调用了转换构造函数,因此前者优先。
练习14.52:在下面的加法表达式中分别选用了哪个operator?列出候选函数、可行函数及为每个可行函数的实参执行的类型转换。
struct longDouble {
//用于演示的成员operator+; 在通常情况下+s是个非成员
longDouble operator+(const SmallInt&);
//其他成员与14.9.2节一致
longDouble operator+(longDouble&, double);
对于ld=si+ld,由于LongDouble不能转换为SmallInt,因此Smallint的成员operator+和friend operator都不可行。
由于Smallint不能转换为LongDouble,LongDouble的成员operator+和非成员operator+也都不可行。
由于SmallInt可以转换为int, LongDouble了可以转换为float和double,所以内置的operator+(int, float)和operator+(int, double)都可行,会产生二义性。
对于ld=ld+si,类似上一个加法表达式,由于Smallint不能转换为double,LongDouble也不能转换为SmallInt,因此SmallInt的成员operator+和两个非成员operator+都不匹配。
LongDouble的成员operator+可行,且为精确匹配。
SmallInt可以转换为int,longDouble可以转换为float和double,因此内置的operator+(float, int)和operator(double, int)都可行。但它们都需要类型转换,因此LongDouble的成员operator+优先匹配。
练习14.53:假设我们已经定义了如第522页所示的SmallInt,判断下面的加法表达式是否合法。如果合法,使用了哪个加法运算符?如果不合法,应该怎样修改代码才能使其合法?
double d = s1 + 3.14;
内置的operator+(int, double)是可行的,而3.14可以转换为int,然后再转换为SmallInt,所以SmallInt的成员operator+也是可行的。两者都需要进行类型转换,所以会产生二义性。改为:double d = s1 +Smallint(3.14);即可。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'

我要回帖

更多关于 select distinct 多列 的文章

 

随机推荐