楼主 gouweicao78 |
LOOKUP函数有一个经典的条件查找解法,通用公式基本可以写为:
1、公式中的2、1、0等数字有什么含义,明明在查找条件与这3个数字根本毫无联系,怎么能得到正确结果? 2、明明LOOKUP函数说明需要“升序”查找,否则可能无法返回正确的值,上面这种解法又是如何得改变这一说法呢? 3、据说LOOKUP函数的查找顺序是“二分法”,并且有流程图可循,是否可以结合此例进行讲解? 【函数帮助信息摘录】 语法:LOOKUP(lookup_value, lookup_vector, result_vector) 1、[要点] lookup_vector 中的值必须以升序排列:...,-2, -1, 0, 1, 2, ..., A-Z, FALSE, TRUE。否则,LOOKUP 可能无法返回正确的值。大写文本和小写文本是等同的。 2、如果 LOOKUP 函数找不到 lookup_value,则它与 lookup_vector 中小于或等于 lookup_value 的最大值匹配。 3、如果 lookup_value 小于 lookup_vector 中的最小值,则 LOOKUP 会返回 #N/A 错误值。 【释疑】简要地说,从逻辑推理来看: 1、首先,条件是一组逻辑判断的值或逻辑运算得到的由TRUE和FALSE组成或者0与非0组成的数组,因而:1/(条件)的作用是用于构建一个由1或者#DIV!0错误组成的值。 2、根据LOOKUP函数说明中的这一条: 也就是说,要在一个由1和#DIV!0组成的数组中查找2,肯定找不到2,因而将返回小于或等于2的最大值(也就是1)匹配。 为什么要用2来查找1或用1来查找0呢?因为如果有多个与第1参数相等的值,则Lookup就不一定返回“最后一个”所对应的记录,所以必须养成一个良好习惯, 而不要用:LOOKUP(1,1/(条件),……,或LOOKUP(,0/(条件),…… 3、如果有多个满足条件的纪录,为何只返回最后一个,而不是第一个或其他呢?这个解释就需要二分法流程图的模拟了。而对于一般使用者来说,只需要记住“查找满足条件的最后一个记录”可以使用通用公式
gouweicao78《Lookup函数二分法模拟器》http://www.exceltip.net/thread-285-1-1.html willin2000修正后的《LOOKUP查找策略完整流程图》http://www.exceltip.net/thread-308-1-1.html |
2楼 gouweicao78 |
示例: 用LOOKUP查找2个条件的数据.rar 如图: 公式:
一、需要明白的几个含义: 1、posi——表示节点号n,A(posi)表示第n个值,比如posi=2,则表示LOOKUP第2参数数组中的第2个值; 2、X——表示Lookup的第一个参数,即查找的值,也就是上述公式中的“2”; 3、TYPE——表示数据类型,比如:数值、文本、逻辑值、错误值等; 4、left、right——表示二分法取值范围,即左边从数组的第几个值开始取,右边截止到数组的第几个值。初始状态下left=1,right=N表示从第1到第N整个数组所有的值都算。 上例中:1/(条件)得到的数组为:
二、需要注意的问题 上面的posi、left、right都是变量,在流程图中,根据规则不断修正从而得到下一步的posi点,而LOOKUP函数最终也是通过定位最后的posi点来返回查找结果的。 模拟动画如下(请单击动画或下载后观看,以便获得更佳效果):二分法流程图演示.gif |
3楼 swallow5121 |
貌似用斑竹提到的两种公式,lookup_vector不需要按升序排列,不知道是不是这样,请斑竹及各位高手指导一下。 |
4楼 gouweicao78 |
1、LOOKUP为什么需要lookup_vector升序排列? 从二分法的角度来说,数据以升序排列的方式是最合理的,就像我们翻字典可以根据首字拼音字母直接翻到附近,大大缩小需要查找的范围,从而相比从第1个到最后1个查找的“遍历法”来说,是一个非常高效的算法。 举个例子来说:要查字母C,首先第一次二分法是它属于A~M,然后再属于A~G,接着属于A~D,然后再属于C~D,最后敲定为C。也就是大约为5次的查找。假如,我们把字典反过来了(降序排列了),那么LOOKUP就傻眼了,有兴趣可以按照流程图对照走一下,算算大约几次。 2、LOOKUP为什么不需要lookup_vector升序排列? 因为LOOKUP用的是二分法,它根据每一个posi(流程图中的节点)的数据情况决定下一步的流程,即便不是升序排列,它也是如此查找。 3、所谓“高效”,是指LOOKUP本身这种运算是高效的,但是: 1/(条件)——这个首先是条件判断,比如1/(A1:A100="张三"),首先运算100次比较,得到逻辑值,接着运算100次除法,得到1或#DIV!0,最后才是LOOKUP的二分法。 因而,实际上本帖解析的这个解法,并不是“高效”的解法。 综上所述:升序,是为了更高效地运作二分法;此处的“二分法”并非严格意义的二分法,如果给了它并非升序的数据,它也会按照流程来运算。 |
5楼 swallow5121 |
我试了试,如果lookup_vector中没有lookup_value ,但是有小于lookup_value的最大值,用斑竹提供的公式得到的是#N/A 错误。不知道斑竹提供的公式是不是有一定的局限,也就是说lookup_vector中必须有lookup_value的值。 |
6楼 gouweicao78 |
得到#N/A错误,在流程图中就给出这样的可能啊,你对照流程的走法去算: 比如共10个数据,那么N=10,left=1,right=10,第一个posi=int((left+right)/2)=5,……………… 然后判断第5个数据的数据类型是否与lookup_value相同,数据的大小情况如何,再继续判断下一步流程。 |
7楼 swallow5121 |
那如果lookup_vector不是按照升序排列,并且lookup_vecto中没有lookup_value的值,我要查找lookup_value的话该怎么办呢。 |
8楼 gouweicao78 |
呵呵,一句话,按照流程走。 =LOOKUP("Z",{"A","E","B"}),就符合你说的那种情况,按照流程走最终找到最后一个记录,因为Z比A、E、B都“大”。 =LOOKUP(1,0/(条件),……)也是如此,因为1比0/(条件)的结果(0和#DIV!0,同类型的只有0)都大。 把1换为2,把0换为1也是一个道理。 |
9楼 swallow5121 |
可是这样也不能得到正确的答案啦,就像斑竹举的例子里一样,1比0/(条件)的结果始终为false,导致最终的结果还是#N/A ,而正确的答案不是应该为“E”么。 |
10楼 gouweicao78 |
如果找不到,也就是(条件)判断都是FALSE,例如: =LOOKUP(1,0/("Z"={"A","E","B"}),{"A","E","B"})——找到最后一个Z的记录,当然是找不到,导致最终结果为#N/A!错误。 但=LOOKUP("Z",{"A","E","B"})不一样 left=1、right=3,第一个节点为int((1+3)/2)=2,即字母E与Z相比,比Z小。 下一步判断posi(就是2)是否小于right(3),即是否最后一个记录,不是最后一个记录则left=posi+1=2+1=3,接下来:新的posi=int((3+3)/2)=3,也就是字母B,还是比Z小。 下一步判断posi(就是3)是否小于right(3),因为是最后一个记录,则返回A(posi)就是第3个记录B 走一下流程图就知道了,如图: |
11楼 linghaodu |
一群匪夷所思的牛人 |
12楼 yncxxmj |
讲的非常好。 |
13楼 herenqing |
看不懂!有待学习! |
14楼 微风 |
非常感谢 |
15楼 wangqilong1980 |
谢谢分享,收藏学习 |
16楼 庭院幽幽 |
天哪,好复杂,还是耐心学吧 |
17楼 wangg913 |
好帖子,可说是巅峰之作。 当然,更是合众人之智。 希望有一些有针对的例子以为佐证。 |
18楼 gouweicao78 |
佐证之事,既然这个流程图已经推理论证出来,也就是符合任何一个这类的公式,任意抓一个来都是例子,都可以套上去验证。 |
19楼 wubaiwan |
好贴,从未见过 |
20楼 张啸宁 |
帖子很好,可惜我能力有限,实在看不懂。 |
21楼 taotao740425 |
看不懂,只得多学 |
22楼 远古石器 |
|
23楼 ccf |
很细致的解释,好好研读!谢谢! |
24楼 snowangle007 |
好复杂啊!只能先收藏了,然后慢慢消化。 |
25楼 cmf2011 |
好复杂呀,楼主,麻烦告诉哪里有详细的举例。谢谢! |
26楼 tdjxxdkj |
是不是必须弄明白这个二分法,实在是看不懂啊。不过非常感谢楼主的耐心。 |
27楼 tongxinwu |
学习了 但看的还是有些晕 要慢慢消化 |
28楼 peakchu |
先收藏了,等下自己研究 |
29楼 LoveJinLee |
看这个GIF 感觉LOOKUP的查找原理,比原有的“二分法”要复杂一些。。 还要比较type |
30楼 gouweicao78 |
这个论证过程是神马和浮云, 大家只需要记住这个用法和注意点: 第1参数要比第2参数大 条件是数组运算,所以建议即便是2007以上版本也不要用整列的数组运算 |
31楼 lpzxhjp |
草版主,怎么哪儿都有你的身影? |
32楼 双飞叶 |
比较深奥的帖子,看不是太 懂 |
33楼 jlf2003 |
很细致的解释,好好研读!谢谢! |
34楼 kmbobo |
草版主 对excel的使用已经出神入化了!pfpf |
35楼 Rongson_Chart |
草版,你讲的很好~~我太菜了~~学了个皮毛~~~ |
36楼 uhilt |
真正围观中...-_- |
37楼 玉丫头 |
把这个当图表研究,很快就 |
38楼 好大一棵树王玉 |
=LOOKUP(1,0/("Z"={"A","E","B"}),{"A","E","B"},看到这纠结了一下,后来明白了,0/("Z"={"A","E","B"}),结果是DIV/0!,所以返回N/A错误!如果有一个返回0,那么,就会有结果了! |
39楼 hustclm |
看的头大了 |
40楼 小风筝 |
终于弄明白是什么意思了。1/()或者0/()这里的1和0不是数字1和0,是逻辑值true和flase。 |
41楼 小风筝 |
整明白了 |
42楼 小风筝 |
1/(条件)这个用法真是太灵活了 |
43楼 飞鱼fish |
今天用这个公式解决了问题,但是要真正理解还得把这帖子翻来覆去的读读啊 |
44楼 buwenhl |
学习中 |
45楼 feisail |
加深了理解。 |
46楼 sunny_8848 |
多谢,学习了 |
47楼 fish-2013 |
解析得非常详细,有点明白1/(条件)这个公式了 |
48楼 yeminqiang |