精华内容
下载资源
问答
  • 今天分享几数据分析中经常需要用到的重要函数。 掌握这些函数可以帮助我们保持代码整洁并且避免重复造轮子。准备工作导入numpyimport numpy as np示例数据本文以二分类任务为例,通常我们的model会输出预测的概率...

    dadb09898981ef8b91fbb622dbcf482f.png

    Numpy 功能十分强大,很多我们想要的复杂操作都有实现。 今天分享几个数据分析中经常需要用到的重要函数。 掌握这些函数可以帮助我们保持代码整洁并且避免重复造轮子。

    准备工作

    导入numpy

    738b39830b25913c7cd231cc132ac074.png
    import numpy as np

    示例数据

    本文以二分类任务为例,通常我们的model会输出预测的概率,得到概率后需要进行后续的处理,比如:

    • 根据阈值,将概率大于某个阈值的label设置为1,小于阈值的设置为0 • 在模型诊断过程中,找出满足某些条件的样本

    本文使用的示例数据如下:

    predict_prob = np.array([0.1,0.3,0.7,0.4,0.9])

    where()

    np.where() 方法可以帮助我们找到array中满足条件的元素的位置。现在我们可以使用np.where()找出所有预测概率大于0.5的的元素了:

    predict_prob = np.array([0.1,0.3,0.7,0.4,0.9])
    np.where(predict_prob > 0.5)
    # output:array([2, 4]),)

    如果我们想将所有概率大于0.5的元素替换为1,否则替换为0,该怎么做呢?

    一个 简单粗暴的方式 是先用上面的方法分别找出array中概率大于或者小于0.5的索引,然后再对这些位置的元素重新赋值。

    其实,np.where() 一个函数就能完成所有的操作,只需要添加两个参数:

    • 第一个参数是满足条件替换的值 • 第二个参数是不满足条件替换的值

    predict_prob = np.array([0.1,0.3,0.7,0.4,0.9])
    np.where(predict_prob > 0.5, 1, 0)
    # output: array([0, 0, 1, 0, 1])

    argmin()、argmax()、argsort()

    np.argmin()、np.argmax()方法会返回array中最小或最大的元素索引,对示例数据运行结果如下:

    predict_prob = np.array([0.1,0.3,0.7,0.4,0.9])
    
    np.argmax(predict_prob)
    # output: 4
    np.argmin(predict_prob)
    # output: 0

    我们成功找到了array中最大最小的元素索引,那怎样找到前n个最大的或最小的值呢?

    现在该轮到np.sort()上场了

    predict_prob = np.array([0.1,0.3,0.7,0.4,0.9])
    np.argsort(predict_prob)
    # output: array([0, 1, 3, 2, 4])

    np.argsort()方法还支持多维数据的排序,感兴趣的可以自行查看 Numpy官方文档 [1]

    intersect1d()

    intersect1d()要做的是,它会找出两个array中的交集,这个函数和前面的几个函数不同,返回的不是索引位置,而是array中的实际值。

    本函数我们使用新的 示例数据:

    arr1 = np.array([1,2,4,4,6])
    arr2 = np.array([2,3,4,5,6])

    现在,我们可以使用intersect1d()找出两个数组共同的元素了:

    np.intersect1d(arr1, arr2)
    # output: array([2, 4, 6])
    展开全文
  • 今天跟大家分享条件查找最常用的8个方法,如果你以前不懂,现在看看这篇文章,绝对可以给你带来收获~下图是一个学科成绩表,我们需要通过左表的姓名和学号两个条件在右表中查找对应的成绩并返回到左表的E列中。...

    Excel中的多条件查找,其实不是很难,很多小伙伴都知道查找用lookup、vlookup函数,但具体怎么使用却不知所措。

    今天跟大家分享多条件查找最常用的8个方法,如果你以前不懂,现在看看这篇文章,绝对可以给你带来收获~

    下图是一个学科成绩表,我们需要通过左表的姓名和学号两个条件在右表中查找对应的成绩并返回到左表的E列中。

    389d992340e0e39cc1a8be46e9710126.png

    方法一:使用LOOKUP函数。

    具体操作步骤如下:

    1、选中E2单元格 -- 在编辑栏中输入公式“=LOOKUP(1,0/(A2=$G$2:$G$11)*(B2=$H$2:$H$11),$I$2:$I$11)”-- 按回车键回车,并将公式下拉填充至E11单元格。

    ce493ca3ee32cbf7c71793f7e5c7d45d.png

    2、动图演示如下。

    248f572be0e1e5a4e870a81cc3bdc940.gif

    3、公式解析。

    (1)(A2=$G$2:$G$11)*(B2=$H$2:$H$11):

    首先,将A2单元格的内容与G2:G11单元格区域的内容作对比,将B2单元格的内容与H2:H11单元格区域的内容作对比。如果A2单元格的内容与G2:G11单元格区域的内容相等,B2单元格的内容与H2:H11单元格区域的内容相等,则返回TRUE,不相等时,返回FALSE。根据逻辑值TRUE=1,FALSE=0,所以这部分公式得到的结果可能有3种情况:0*1;1*1;1*0。公式A2=$G$2:$G$11返回的结果为{0;0;0;0;0;1;0;0;0;0},因为只有G6单元格的值与A2相等。公式B2=$H$2:$H$11返回的结果为{0;0;0;0;0;1;0;0;0;0},因为只有H6单元格的值与B2相等。所以公式(A2=$G$2:$G$11)*(B2=$H$2:$H$11)返回的结果为{0;0;0;0;0;1;0;0;0;0}。

    3cba09cd7b91ff5b5cd1ab4344fd662a.png

    (2)0/(A2=$G$2:$G$11)*(B2=$H$2:$H$11):

    LOOKUP函数,如果要精确查找,第2个参数查找区域必须升序排序,得到的结果才是正确的。但我们这里没有升序排序,用到的是LOOKUP函数的二分法原理,用0来除以(A2=$G$2:$G$11)*(B2=$H$2:$H$11)这个公式的结果值,这里只会产生两种情况:0/0或0/1。而在除法运算中,被除数不能为0,也就是分母不能为0,所以在Excel中,0/0会得到错误值#DIV/0!,而0/1的结果为0。所以该公式返回的结果为{#DIV/0!;#DIV/0!;#DIV/0!;#DIV/0!;#DIV/0!;0;#DIV/0!;#DIV/0!;#DIV/0!;#DIV/0!}。

    dd9f1f35e06c428d2232e0845d96573b.png

    (3)=LOOKUP(1,0/(A2=$G$2:$G$11)*(B2=$H$2:$H$11),$I$2:$I$11):

    根据第(2)步公式返回的结果{#DIV/0!;#DIV/0!;#DIV/0!;#DIV/0!;#DIV/0!;0;#DIV/0!;#DIV/0!;#DIV/0!;#DIV/0!},再根据LOOKUP函数的查找原理,忽略错误值查找,所以该公式的意思是,找到与1最接近的值,在第(2)步返回的结果数组中,错误值被忽略,只有一个0,0<1,因此返回I2:I11单元格范围内的第6个数据,即I7单元格的内容“68”。

    方法二:使用VLOOKUP函数。

    具体操作步骤如下:

    1、选中E2单元格 -- 在编辑栏中输入公式“=VLOOKUP(A2&B2,IF({1,0},$G$2:$G$11&$H$2:$H$11,$I$2:$I$11),2,0)”-- 按组合键“Ctrl+Shift+Enter”回车 -- 并将公式下拉填充至E11单元格。

    fd7d2adaf1938d0d472c8b0571aeba3d.png

    2、动图演示如下。

    13b828cd0f7e03e234701e1a1ea0d50f.gif

    3、公式解析。

    (1)A2&B2:

    我们都知道,VLOOKUP函数查找时查找值默认只能有一个条件,我们这里是多条件查找,所以可以通过文本连接符&将两个条件连接起来作为新的查找值。新的查找值也就是“姓名学号”。

    d2aaa2f07e43aab13c8deed371fd8536.png

    (2)IF({1,0},$G$2:$G$11&$H$2:$H$11,$I$2:$I$11):

    {1,0}相当于{TRUE,FALSE}。所以该公式就有两种情况:第一种情况:=IF(1,$G$2:$G$11&$H$2:$H$11,$I$2:$I$11),这种情况返回G2:G11单元格区域内容和H2:H11单元格区域内容合并后的结果。第二种情况:=IF(0,$G$2:$G$11&$H$2:$H$11,$I$2:$I$11),这种情况返回I2:I11单元格区域内容。所以{1,0}相当于重新构建了两列数据,第1列数据是以G2:G11单元格区域内容和H2:H11单元格区域内容合并后的数据,第2列数据是I2:I11单元格区域构建的数据,如下图所示。

    a291a5d921412fc5a24e971be04fe17b.png

    (3)=VLOOKUP(A2&B2,IF({1,0},$G$2:$G$11&$H$2:$H$11,$I$2:$I$11),2,0):

    第一个参数查找值“A2&B2”,要返回的结果值在IF构建的新数据区域中,属于第2列,所以第3个参数为2,这里是精确查找,所以第4个参数为0或者FALSE。

    方法三:使用OFFSET函数+MATCH函数。

    具体操作步骤如下:

    1、选中E2单元格 -- 在编辑栏中输入公式“=OFFSET($I$1,MATCH(A2&B2,$G$2:$G$11&$H$2:$H$11,0),)”-- 按组合键“Ctrl+Shift+Enter”回车 -- 并将公式下拉填充至E11单元格。

    2662db74660a2738c69233aaed7bb0b6.png

    2、动图演示如下。

    b0de1662e4a2256672f9279c23eaeb2f.gif

    3、公式解析。

    (1)MATCH(A2&B2,$G$2:$G$11&$H$2:$H$11,0):

    将A2单元格的姓名与B2单元格的学号通过用文本连接符合并作为新的查找内容,将G列的姓名和H列的学号通过文本连接符合并作为新的查找区域,0表示精确查找。该公式返回的结果为“6”。

    82377fb0da9c7d9da10b1a80dca8b8e2.png

    (2)=OFFSET($I$1,MATCH(A2&B2,$G$2:$G$11&$H$2:$H$11,0),):

    OFFSET函数是指以指定的单元格引用为参照系,通过给定偏移量得到新的引用。返回对单元格或单元格区域中指定行数和列数的区域的引用。 返回的引用可以是单个单元格或单元格区域。 可以指定要返回的行数和列数。该公式表示以$I$1为参照单元格,通过MATCH查找出来顺序作为向下偏移的行数,偏移列数量省略表示不偏移,第三个、第四个参数省略表示只返回一个单元格区域。第(1)步MATCH函数得到的结果为6,所以向下偏移6行时找到“68”。

    方法四:使用SUM函数。

    具体操作步骤如下:

    1、选中E2单元格 -- 在编辑栏中输入公式“=SUM((A2=$G$2:$G$11)*(B2=$H$2:$H$11)*($I$2:$I$11))”-- 按组合键“Ctrl+Shift+Enter”回车 -- 并将公式下拉填充至E11单元格。

    ad3aacd3f4ece162d05db859249cc1d1.png

    2、动图演示如下。

    e3986a9b056126b05303c24d3b0eef1e.png

    3、公式解析。

    (1)A2=$G$2:$G$11:

    判断A2单元格的内容是否与G2:G11单元格区域的内容相等,如果相等,返回TRUE,否则,返回FALSE。该公式返回一个逻辑值数组{FALSE;FALSE;FALSE;FALSE;FALSE;TRUE;FALSE;FALSE;FALSE;FALSE}。

    3ca367629da5615b5f7bf1c22388a7f2.png

    (2)B2=$H$2:$H$11:

    判断B2单元格的内容是否与H2:H11单元格区域的内容相等,如果相等,返回TRUE,否则,返回FALSE。该公式返回一个逻辑值数组{FALSE;FALSE;FALSE;FALSE;FALSE;TRUE;FALSE;FALSE;FALSE;FALSE}。

    aa78dbe0509ed7eef3c6c48cbcd07157.png

    (3)=SUM((A2=$G$2:$G$11)*(B2=$H$2:$H$11)*($I$2:$I$11)):

    3个值相乘,只有当前面2个值都为TRUE时,最后的结果才为TRUE,而TRUE=1,FALSE=0,从上面2步中,我们可以看到只有第6个值为TRUE,其余都为FALSE。再与I2:I11的值相乘,最后通过SUM函数将得到的值相加起来,最后的结果“68”,将公式往下填充,即可得到其他单元格的值。

    78a2c9b7554b9886a9b3f3291ba87c74.png

    方法五:使用SUMPRODUCT函数。

    具体操作步骤如下:

    1、选中E2单元格 -- 在编辑栏中输入公式“=SUMPRODUCT((A2=$G$2:$G$11)*(B2=$H$2:$H$11)*($I$2:$I$11))”-- 按Enter键回车 -- 并将公式下拉填充至E11单元格。

    95d75bd82762aa26a02004943c17f00e.png

    2、动图演示如下。

    5afbbca9856f5c80bdb8161cd1834331.gif

    3、公式解析。

    (1)A2=$G$2:$G$11:

    判断A2单元格的内容是否与G2:G11单元格区域的内容相等,如果相等,返回TRUE,否则,返回FALSE。该公式返回一个逻辑值数组{FALSE;FALSE;FALSE;FALSE;FALSE;TRUE;FALSE;FALSE;FALSE;FALSE}。

    6084faa12c874ef1a2d365251d72850b.png

    (2)B2=$H$2:$H$11:

    判断B2单元格的内容是否与H2:H11单元格区域的内容相等,如果相等,返回TRUE,否则,返回FALSE。该公式返回一个逻辑值数组{FALSE;FALSE;FALSE;FALSE;FALSE;TRUE;FALSE;FALSE;FALSE;FALSE}。

    883533bb9e7aa0272e01216fcd605bc9.png

    (3)=SUMPRODUCT((A2=$G$2:$G$11)*(B2=$H$2:$H$11)*($I$2:$I$11)):

    3个值相乘,只有当前面2个值都为TRUE时,最后的结果才为TRUE,而TRUE=1,FALSE=0,从上面2步中,我们可以看到只有第6个值为TRUE,其余都为FALSE。再与I2:I11的值相乘,最后通过SUMPRODUCT函数将每个数组对应元素的值相乘,最后再相加,得到的结果为“68”,将公式往下填充,即可得到其他单元格的值。

    172fca8eb5fc30f61dc8fa39720b765c.png

    方法六:使用MAX函数。

    具体操作步骤如下:

    1、选中E2单元格 -- 在编辑栏中输入公式“=MAX((A2=$G$2:$G$11)*(B2=$H$2:$H$11)*($I$2:$I$11))”-- 按组合键“Ctrl + Shift +Enter”回车 -- 并将公式下拉填充至E11单元格。

    46f803696f78d83444fa9e3978a1ecbb.png

    2、动图演示如下。

    cecd619b6910e2b148784c3cd632e248.gif

    3、公式解析。

    (1)A2=$G$2:$G$11:

    判断A2单元格的内容是否与G2:G11单元格区域的内容相等,如果相等,返回TRUE,否则,返回FALSE。该公式返回一个逻辑值数组{FALSE;FALSE;FALSE;FALSE;FALSE;TRUE;FALSE;FALSE;FALSE;FALSE}。

    298192da7c79c6e61a2b11f35d2c6073.png

    (2)B2=$H$2:$H$11:

    判断B2单元格的内容是否与H2:H11单元格区域的内容相等,如果相等,返回TRUE,否则,返回FALSE。该公式返回一个逻辑值数组{FALSE;FALSE;FALSE;FALSE;FALSE;TRUE;FALSE;FALSE;FALSE;FALSE}。

    65dab487dc4bc1bfcb3685bacc5ee09e.png

    (3)=MAX((A2=$G$2:$G$11)*(B2=$H$2:$H$11)*($I$2:$I$11)):

    将(A2=$G$2:$G$11)*(B2=$H$2:$H$11)*($I$2:$I$11)这3个数组相乘,最后得到的结果为{0;0;0;0;0;68;0;0;0;0},根据MAX函数的原理,找到一组值中的最大值并返回,很显然,结果数组中的最大值为“68”,所以返回的结果为68,将公式往下填充,即可得到其他单元格的值。

    e0d7eaab968162cd288e55bd55a821a5.png

    方法七:使用MIN函数+IF函数。

    1、选中E2单元格 -- 在编辑栏中输入公式“=MIN(IF((A2=$G$2:$G$11)*(B2=$H$2:$H$11),$I$2:$I$11))”-- 按组合键“Ctrl + Shift +Enter”回车 -- 并将公式下拉填充至E11单元格。

    9c53145d2e16f3c63a272a4679591186.png

    2、动图演示如下。

    c88b703489d16503c255f66d58d11b54.gif

    3、公式解析。

    (1)(A2=$G$2:$G$11)*(B2=$H$2:$H$11):

    判断A2单元格的内容是否与G2:G11单元格区域的内容相等,如果相等,返回TRUE,否则,返回FALSE。判断B2单元格的内容是否与H2:H11单元格区域的内容相等,如果相等,返回TRUE,否则,返回FALSE。该公式返回一个0和1组成的数组{0;0;0;0;0;1;0;0;0;0}。

    5adb413fbd94e2d562e593d3739538ec.png

    (2)IF((A2=$G$2:$G$11)*(B2=$H$2:$H$11),$I$2:$I$11):

    如果(A2=$G$2:$G$11)*(B2=$H$2:$H$11)为TRUE,返回$I$2:$I$11单元格区域的内容,如果为FALSE,返回空。所以该公式返回的结果为{FALSE;FALSE;FALSE;FALSE;FALSE;68;FALSE;FALSE;FALSE;FALSE}。

    5b4bea4cd2a9718e9349535ac66d3df6.png

    (3)=MIN(IF((A2=$G$2:$G$11)*(B2=$H$2:$H$11),$I$2:$I$11)):

    MIN函数是返回一组值中的最小值,空单元格、逻辑值和文本将被忽略。由第(2)步可知,只有68是数值,所以返回的结果就是68,将公式往下填充,即可得到其他单元格的值。

    方法八:使用INDEX函数+MATCH函数。

    1、选中E2单元格 -- 在编辑栏中输入公式“=INDEX($I$2:$I$11,MATCH(A2&B2,$G$2:$G$11&$H$2:$H$11,0))”-- 按组合键“Ctrl+Shift+Enter”键回车 -- 并将公式下拉填充至E11单元格。

    94f27a1f5b4394101db8f706b52b9274.png

    2、动图演示如下。

    768271450fc6710340e53f2b9f0916c2.gif

    3、公式解析。

    (1)$I$2:$I$11:

    要返回的结果所在的单元格区域。该公式得到一组数组{80;71;82;84;70;68;90;74;70;89}。

    920bdb5bfae5cc96e47ac4b3573e6be0.png

    (2)MATCH(A2&B2,$G$2:$G$11&$H$2:$H$11,0):

    将A2单元格的姓名与B2单元格的学号通过用文本连接符合并作为新的查找内容,将G列的姓名和H列的学号通过文本连接符合并作为新的查找区域,0表示精确查找。该公式返回的结果为“6”。

    9f9abe7f70d021bab168f284e129eaf7.png

    (3)=INDEX($I$2:$I$11,MATCH(A2&B2,$G$2:$G$11&$H$2:$H$11,0)):

    INDEX函数的作用是:返回表或区域中的值或值的引用。上述公式由第(1)步和第(2)步得到的结果,可将公式写成=INDEX({80;71;82;84;70;68;90;74;70;89},6)。6是行号,也就是从在{80;71;82;84;70;68;90;74;70;89}这组值中返回第6行单元格值的引用,所以为68,将公式往下填充,即可得到其他单元格的值。

    以上就是多条件查找的8中方法,不知不觉本文也写了6000左右字,希望亲可以转发和点赞鼓励支持一下。如有不懂之处,可在评论区留言!更多常用Excel函数组合,请持续关注本头条号!

    22ce893c7a84f5128b344c8e5005a39e.png

    您的每一份赞赏、转发、评论、点赞、收藏都将成为我们写出更多优质教程的动力!感激不尽!

    展开全文
  • 上一篇介绍了如何实现数据的复杂查询,但主要介绍了查询条件设置,并没有涉及如何汇总处理数据,今天一起来了解一下如何在Access中汇总处理数据。▍如何汇总数据Excel中是通过函数或透视表来汇总处理数据的。在...

    66b89930946e045de0416f204d25a96d.png

    上一篇介绍了如何实现数据的复杂查询,但主要介绍了查询条件的设置,并没有涉及如何汇总处理数据,今天一起来了解一下如何在Access中汇总处理数据。

    如何汇总数据

    Excel中是通过函数或透视表来汇总处理数据的。在Access中处理原理也接近,需要在查询中两步实现

    步骤分组汇总

    在查询设计中首先完成字段设计后,点击“设计“选项卡中的“汇总,可以看到在总计一栏出现”Group by”, Group by的含义是分组,作用类似与Excel透视表中的“行字段”;

    如果需要对数据进行计算或者处理,需要继续选择汇总处理的方式以及对应的字段。

    0035632eabb6232720a965bc56778e35.png

    步骤选择汇总方式(或者使用表达式)

    在此例中,选择对字段“地区生产总值进行求和,则汇总方式选择”合计“即可。除此之外,还有多种汇总方式可选。其中的Expression即表达式模式,类似与Excel公式,可以利用函数、运算符进行自定义汇总数据或处理数据,从而生成一个新的字段。

    74fac7b4f272aed2b8adbd647afc203f.png

    上述设置运行后,查询结果为全国各年度的国内生产总值。

    4c5e8df1d4d588f15fb2ea1afbc2f3f1.png

    使用运算符

    无论是设置查询条件还是运算中的表达式,都离不开运算符。常用的运算符包括:算数运算符、比较运算符、逻辑运算符等。

    算术运算符

    基本的算术符号有:+(加法运算),-(减法运算),*(乘法运算),/或\(除法运算),Mod(余数),^(幂运算),在这里重点介绍一下和Excle中的有区别的几个算术运算符
    • 加法运算的两个作用:在Access中加号+除了数据的加法运算之外,还能合并两个文本字段,起到和连接符&同样的作用。但是一般情况下,不建议直接使用+连接字符串,我们举例说明一下+和&的区别:

      比如:123+45运算的结果是168,而123+45的运算结果是12345;连接符&会把所有的变量当作字符转处理,但是加号+是根据变量的数据类型会有所不同。

    be00a56aba880f33771894c030370198.png

    • 两种除法运算符号:左斜杠/表示的是标准的除法运算,右斜杠\同样是除法运算,但只适用于两个同为整型操作数,结果为商数整数。比如表达式10\3 ,运算结果为3;而10/3的运算结果是3.333...

    • 余数运算符号Mod:在Excel中它是作为函数存在的,但是在Access中是作为运算符存在,它的运算结果是余数,比如10 Mod 3的运算结果是1

    比较运算符

    比较运算符包括:(大于),<=(小于或等于),>=(大于或等于),<>(不等于),=(等于),使用比较运算符返回的结果为逻辑值,比如100>99,返回的结果为True,需要注意的是,只要其中的一个参与比较的值为NULL,那么结果均为NULL。

    逻辑运算符和其他

    逻辑运算符主要包括:AND(且),OR(或),NOT(非),关于AND与OR的含义及用法相比大家都比较熟悉,NOT的用法在举例查询非空值IS NOT NULL也使用过。我们再举个例子说明一下:

    比如【NOT =2018】等价于【<>2018

    5601381510daeb256bb7d2038b5d9370.png

    除此以外,IS、LIKE、IN、Between作为一种特殊的运算符,它的运算结果也是逻辑值,所以一般上述的运算符常常在查询的条件中出现。

    使用函数

    函数是数据汇总计算中不可缺少的元素,在Access中也存在函数。

    SQL是标准化的数据库语言,所以Access是支持SQL查询的,大部分SQL涉及到的函数在Access中基本都可以使用。部分函数是我们在Excel中也比较熟悉的,如日期时间函数,字符串处理函数等等,当然这些函数的原理虽然是一样的,但是在语法上会有区别。关于函数的用法下期详解。

    示例文件
    文件名:示例文件_汇总查询
    下载地址:http://mychart.cn/plugin.php?id=mdown:index#/看完有什么心得体会吗?评论区留言告诉我吧!记得点赞哦▍本篇课程地址(免费)http://mychart.cn/plugin.php?id=keke_video_base&ac=course&cid=8

    c708ca077266716c1d240711c5a377d6.png

    • Access多条件高级查询

    • Access两表查询一线牵

    • Access数据查询就是这么简单

    • Access数据的导入与导出

    • Access入门之Access对象

    展开全文
  • 也许你会疑惑,但它确实可以,Windows的回调函数就是这么一个东西,就是那个callback,当满足一定条件的时候就会调用这个回调函数,那怎么知道什么时候才满足这个条件呢?这个不用我们操心,系统会帮我们高效的检查...

                                                                     成员函数指针与回调函数

           首先来提一个问题,函数能作为参数吗?也许你会疑惑,但它确实可以,Windows的回调函数就是这么一个东西,就是那个callback,当满足一定条件的时候就会调用这个回调函数,那怎么知道什么时候才满足这个条件呢?这个不用我们操心,系统会帮我们高效的检查,这个检查就是监听器的工作?有很多名词没听过?没关系,今天我讨论的主题不是这个。听过那最好啦!那么设置一个回调函数的时候,是不是有点烦,参数类型啊,参数个数啊,返回类型啊一定要一致,还要加一个callback声明,否则就会调用失败!!!切记!!!

           听起来,callback函数有点玄,当你条件满足的时候才去调用,所以很高效,那它是怎么实现的呢?考虑下面的代码:

    typedef void (*ptrFn)(char);

    ptrFn pFn;

    char keyDown = 0;

    void Function(charkey)

    {

           switch(key)

           {

           case 'd':cout<<"Dwas pressed!Move Right!"<<endl;break;

           case 's':cout<<"Swas pressed!Move Down!"<<endl;break;

           case 'w':cout<<"Wwas Pressed!Move Up!"<<endl;break;

           case 'a':cout<<"Awas Pressed!Move Left!"<<endl;break;

           default:break;

           }

    }

    void SetCallBack()

    {

           keyDown = getch();

           while(keyDown!= '0')

           {

                  pFn(keyDown);

                  keyDown = getch();

           }

    }

    void main()

    {

           pFn = Function;

           SetCallBack();

    }

           上面的代码不难理解,就是按下wasd来控制人物的移动,因为用的getch()函数读取一个字符(按下一个字符后,不需要按回车),要记得加入#include <conio.h>上面的几行代码有点回调函数的味道了,只是windows的回调函数比这个复杂多了,咱们先不讨论那个!

           先来理解下上面的代码,typedef void (*ptrFn)(char);typedef重命名函数指针,ptrFn指向的是一个空返回类型,参数为 char 的函数,然后我们要设置自己的回调函数的时候就可以这样写:

    void 函数名 (char 参数名)

    {

          //要执行的代码

    }

    然后在main()主函数里,将pFn = 函数名,这样就可以调用你设置的函数了!别看了,自己先去调试一下,理解好了再往下看!不然你又会迷迷糊糊的了!如果已经理解的同学,继续前进!

           那么我想将上面的回调函数放在类里面,作为成员函数来调用行不行呢?你马上会想到以下的代码:

    class Game

    {

    private:

           floatx,y;

    public:

           voidFunction(char key);

    };

    void Game::Function(charkey)

    {

           switch(key)

           {

           case 'd':cout<<"Dwas pressed!Move Right!"<<endl;break;

           case 's':cout<<"Swas pressed!Move Down!"<<endl;break;

           case 'w':cout<<"Wwas Pressed!Move Up!"<<endl;break;

           case 'a':cout<<"Awas Pressed!Move Left!"<<endl;break;

           default:break;

           }

    }

    void main()

    {

           Game game;

           pFn = game.Function;

           SetCallBack();

    }

    你会发现无法编译通过,说什么:无法从“void (__thiscall Game::* )(char)”转换为“ptrFn”!!!

    这是为什么?理解一下错误信息,无法从(Gme::*)(char)转换为ptrFn,也就是说game.Function是Game::*类型的,而ptrFn必须指向的是void返回类型的,因为Function是classGame里面的东西,所以多了一个域的作用,而我们typedef void(*ptrFn)(char);的时候指明的是没有域作用的,也就是全局的,也就说“域”不匹配,当然无法编译通过!!!

    那怎么办,既然“域”不匹配,那么我们就将它匹配行啦。那么指明匹配?typedef void (*ptrFn)(char);将这个改成:

    typedef void (Game::*ptrFn)(char);这样?

    我们发现这样还是不行,会出现一大堆的错误,就算这样能行,那么我们就一定得实例化一个对象,才能正常使用,而回调函数是不能通过实例化再来调用的。它必须得在程序运行的时候就存在了,而且我们也不可能改成这样typedef void (Game::*ptrFn)(char);如果这个是windows写的,那你怎么改?所以我们得另寻它法。

          匹配typedef的不行,那么只能匹配Game里面的了,那么怎么匹配,因为tepedef需要指向的全局的,那么怎么Game::Function改成全局的?其实不难,将它声明为静态的而且是public的就行了,这样的话,只要在使用Function的时候加个域说明Game::就行了,所以就有了下面的代码:

    class Game

    {

    private:

           floatx,y;

    public:

           static void Function(charkey);

    };

    void Game::Function(charkey)

    {

           switch(key)

           {

           case 'd':cout<<"Dwas pressed!Move Right!"<<endl;break;

           case 's':cout<<"Swas pressed!Move Down!"<<endl;break;

           case 'w':cout<<"Wwas Pressed!Move Up!"<<endl;break;

           case 'a':cout<<"Awas Pressed!Move Left!"<<endl;break;

           default:break;

           }

    }

     

     

    void main()

    {

           pFn = Game::Function;

           SetCallBack();

    }

    跟之前的代码没什么区别,只是在Game里的Function()加了一个static,

    main()主函数里面加了一个域说明pFn = Game::Function;因为Game::Function()是静态的,所以不需要实例化一个对象,因为它程序一运行的时候已经被创建了。

          

    展开全文
  • EXCEL函数公式集

    热门讨论 2010-03-16 03:26:38
    把有六百多个单元格的一列,变成一页的多列 将N列变M列公式归纳为 一列变四列 四列变一列 重复四次填充 多行数据排成一列 将单元格一列分为多列 首写字母大写 把单元格编号中的小写字母变成大写字母 让姓名左右对齐 ...
  • Spark自带的JdbcRDD,只支持Long类型的分区参数,分区必须是一...主要实现思路:把设置查询参数部分改写成可以自定义的函数。这样自己想怎么设置分区参数都可以。直接上代码吧:////////////////////////////...
  • 在数据量很的时候,怎么快速比对出两列数据的不同处,或者查看某一列被另一列占用了多少,当然列也可以比,你只需要&&&拼接成一字符对比就可以了 比对方法: 选择其中一列,比如这里的A列,...
  • 计算机实验报告怎么写 温州大学瓯江学院 实验名称:Excel高级应用(二):教材订购情况分析 实验目的: 1、 掌握Excel 20xx单元格数据的有效性设置 2、 进一步掌握数组公式的使用 3、 掌握条件格式设置 4、 ...
  • 就存在一问题,存在组开始和结束日期时,点击开始时间,怎么把对应结束时间传递给函数,从而限制开始日期<结束日期,禁用不符合条件的日期。 于是想通过 (nzOnOpenChange) 弹出日历和关闭日历的回调事件来...
  • 线程知识点

    2017-06-03 12:40:20
    线程我之总结: 对于临界区(CritialSection)的计数,其计数...初始,未设置owership的怎么判断   1. 第一CreateThread 函数功能:创建线程 函数原型: HANDLEWINAPICreateThread(  LPSECURITY_ATTR
  • //不使用HardExample时必须设置为0,因为特征向量矩阵和特征类别矩阵的维数初始化时用到这值 #define HardExampleNO 433 //继承自CvSVM的类,因为生成setSVMDetector()中用到的检测子参数时,需要用到训练好...
  • 然后又使用一些内存分配技巧使namestr数组用起来好像有多个元素,namelen记录了元素个数。它是怎样工作的?这样是合法的和可移植的吗? 2.8 我听说结构可以赋给变量也可以对函数传入和传出。为什么K&R1却明确说明不...
  • 查询数据,可以多线程同时查询,每次查询都会打开一个新的日志文件的描述符,所以并行的多个读取不会打架。 写入的话,虽然只是append操作,但不确认多线程对文件进行append操作是否安全,所以建议用一个队列,一个...
  • TaskEditor - 任务编辑器,可以自定义任务点,设置任务达成条件多个任务点组成一个任务内容,使用一系列任务内容完成角色扮演的设计。 UI - 用于管理全局的UI实体,以省去手动创建UI实例、销毁UI实例等一系列...
  • 《你必须知道的495C语言问题》

    热门讨论 2010-03-20 16:41:18
    书中列出了C用户经常问的400多个经典问题,涵盖了初始化、数组、指针、字符串、内存分配、库函数、C预处理器等各个方面的主题,并分别给出了解答,而且结合代码示例阐明要点。 《你必须知道的495个C语言问题》结构...
  • 然后又使用一些内存分配技巧使namestr数组用起来好像有多个元素,namelen记录了元素个数。它是怎样工作的?这样是合法的和可移植的吗? 23  2.8 我听说结构可以赋给变量也可以对函数传入和传出。为什么K&R1却明确...
  • │ │ ├─带条件查询报表 │ │ ├─表达式报表 │ │ ├─带二维码/条形码报表 │ │ ├─表头复杂报表 │ │ ├─主子报表 │ │ ├─预警报表 │ │ ├─数据钻取报表 │ ├─图形报表 │ │ ├─柱形图 │ │...
  • 把有六百多个单元格的一列,变成一页的多列 将N列变M列公式归纳为 一列变四列 四列变一列 重复四次填充 多行数据排成一列 将单元格一列分为多列 首写字母大写 把单元格编号中的小写字母变成大写字母 让姓名左右对齐 ...
  • 以前说到BUTTON控件CausesValidation=true/false来设置按钮提交的表单是不是被检验也就是这里的几检验控件,如果CausesValidation=true的话按下按钮就会首先检测是不是都通过了检验控件的检验。 下面再说两点: ...
  • - 而且刚好SpriteC满足“是鼠标位置下层叠元素上最后绘制的那一个”</strong> 这个条件。那么表示SpriteC 的 <code>mouseover</code> 或者 <code>mouseenter</code> 触发条件满足。 - <code>mouseout</code> 的触发...
  • python中线程的使用

    2013-06-05 22:08:12
    (1)在该线程执行的函数中,设置死循环,即while true。当线程调用该函数时,则该函数就会陷入了死循环。当满足某种条件之后,可以通过break退出该循环。本blog中介绍的“双线程高效下载问题”和“线
  • Python中线程的使用

    千次阅读 2012-07-30 20:48:00
    (1)在该线程执行的函数中,设置死循环,即while true。当线程调用该函数时,则该函数就会陷入了死循环。当满足某种条件之后,可以通过break退出该循环。本blog中介绍的“双线程高效下载问题”和“线
  • 用pyqt5设计了一主窗体,...2、在子线程设置变量,通过改变变量的值使循环不满足条件,自动结束 3、设置析构函数 还有别的奇葩。都不行。 今天发现,其实很简单。就是重构主窗体的closeEvent()函数。 def close
  • less循环操作

    2020-08-19 13:18:04
    less循环与js的while语句横向式,其实就是一递归函数配合when函数一起使用,当满足条件将会停下来 .loop(@counter) when (@counter > 0) { width: (10px * @counter); // 一些属性的设置 .loop(@counter - 1) ...
  • 291 在类中使用多个构造函数 292 理解析构函数 293 理解类中的访问关键字 294 使用访问关键字实施封装 295 保持数据成员为私有的 296 理解基类 297 从基类派生一个新类 298 理解多重继承 299 使用基类 300 理解成员...
  • 291 在类中使用多个构造函数 292 理解析构函数 293 理解类中的访问关键字 294 使用访问关键字实施封装 295 保持数据成员为私有的 296 理解基类 297 从基类派生一个新类 298 理解多重继承 299 使用基类 300 理解成员...
  • 291 在类中使用多个构造函数 292 理解析构函数 293 理解类中的访问关键字 294 使用访问关键字实施封装 295 保持数据成员为私有的 296 理解基类 297 从基类派生一个新类 298 理解多重继承 299 使用基类 300 理解成员...
  • 291 在类中使用多个构造函数 292 理解析构函数 293 理解类中的访问关键字 294 使用访问关键字实施封装 295 保持数据成员为私有的 296 理解基类 297 从基类派生一个新类 298 理解多重继承 299 使用基类 300 理解成员...

空空如也

空空如也

1 2 3 4 5
收藏数 88
精华内容 35
关键字:

多个条件函数怎么设置条件