ExcelTip.Net留存知识帖 ---【注:附件之前被网盘供应商清空后,现已修复-现已修复-现已修复为本地下载!】
现在位置:首页 > E文精选 > 函数与公式 > 按数据频率升序提取唯一值

按数据频率升序提取唯一值

作者:绿色风 分类: 时间:2022-08-17 浏览:147
楼主
嘉昆2011
声明:素材来源于Chandoo先生博客,链接如下,
  1. http://chandoo.org/wp/2012/10/04/formula-forensics-no-030/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+PointyHairedDilbert+%28Chandoo.org+-+Learn+Excel+%26+Charting+Online%29
发帖初衷:
1,通过比较几组函数公式,加深对Index(),Match(),Countif()函数的常用变形公式的理解
2,其他相关函数:Large/Small(),Frequency(),Mode.Mult()

问题陈述:
对于一列文本数据,如何利用公式根据频率高低升序排序得到一组唯一序列?

 

1,为了便于测试和学习,定义一个动态名称标签DList:
  1. =Sheet1!$A$2:INDEX(Sheet1!$A:$A,COUNTA(Sheet1!$A:$A))
2,看看提取文字序列经历了哪些演变,各组分函数的功能,能学到些什么
注:例子中IfError()函数主要起排错作用,主要关注IfError()里面的函数。

 

a, 2005年,Gvntw 在帖中归纳总结了Countif函数的经典用法
  1. http://club.excelhome.net/dispbbs.asp?boardid=3&id=93747
  1. =INDEX(A:A,RIGHT(LARGE(COUNTIF(DList,">="&DList)*10^5+ROW(DList),ROW(1:1)),5))
算法思想:利用对关键字先加权后除权思想,实现对序列的升序排列

b, 2009年,Oscar 在帖中实现了相同的功能(升序排列)
  1. http://www.get-digital-help.com/2009/03/27/sorting-text-cells-using-array-formula/
  1. =INDEX(DList,MATCH(SMALL(COUNTIF(DList,"<"&DList),ROW(1:1)),COUNTIF(DList,"<"&DList),0))
算法思想:比较字符间的相对大小,返回字符在序列间的相对位置

c, 2010年,Mike 在VLog中实现了单一升序功能
  1. http://www.youtube.com/watch?v=IZLAzIYfMDU&feature=my_liked_videos&list=LLxSG8yOxCnMWykn8bLPzloQ
  1. =INDEX(DList,MATCH(0,COUNTIF(DList,"<"&DList)-SUM(COUNTIF(DList,D$1:D1)),0))
算法思想:在Oscar的基础上扣除已出现字符在序列中的次数,返回不重复的升序字符串

d, 2012年,Haseeb 在论坛中实现了根据频率高低获取不重复的字符串
  1. http://chandoo.org/forums/topic/ranking-string-data-for-one-column
  1. =INDEX(DList,MODE(IF(ISNA(MATCH(DList,E$1:E1,0)),MATCH(DList,DList,0)*{1,1})))
算法思想:扣除已出现的字符,统计出频率最高的字符在哪个位置
注:*{1,1}模块是为防止Mode()只出现单一序列而设的除错功能,如{1,2,3,4,5,6,7,8,9,10},Mode函数会报错

e, 2012年,Chandoo 在结合Oscar和Haseeb的思想上实现了根据频率高低获取不重复的升序字符串
  1. =INDEX(DList,MATCH(MIN(MODE.MULT(IF(NOT(COUNTIF(G$1:G1,DList)),(COUNTIF(DList,"<"&DList)+{1})*{1,1}))),COUNTIF(DList,"<"&DList)+{1},0))
算法思想:加入Mode.Mult&Min函数是考虑了频率相等时,取字符较小的,即升序,然后返回在字符串中的相对位置。

上述公式中,变化最为精彩的算是Countif()和Match()函数间的相互配合,下面来看看几种常见变形。

Countif(Range, Criteria):在特定区域(Range)内统计满足条件(Criteria)的单元格数量,返回的维度应与满足条件(Criteria)的单元格相等。

1,
  1. =COUNTIF(DList,DList)
  1. {1;2;3;3;1;2;3;3;3;3;2;2}
说明表示:各字符在序列中出现的频率

2,
  1. =COUNTIF(DList,">="&DList)
  2. 或者
  3. =COUNTIF(DList,"<"&DList)+1
  1. {12;8;6;11;3;2;6;11;11;6;8;2}
  2. 或者
  3. {1;5;7;2;10;11;7;2;2;7;5;11}
说明表示:各字符串间可以比较大小,不考虑字母大小写,即数字大小反映升序或是降序

3,
  1. =COUNTIF(DList,E$1:E3)
  1. {0;1;3}
说明表示:统计已经出现的次数;返回看看定义,仿佛清晰了许多

4,
  1. =COUNTIF(G$1:G3,DList)
  1. {0;0;1;1;0;0;1;1;1;1;0;0}
说明表示:对于可扩展的区域,是否出现相应的值,出现为1,没有则为0。可用于去重复值

Match(lookup_value;lookup_array; [match_type]):返回查询值在查询数组中的相对位置,缺省(,0)为精确匹配;返回值的维度应与查询值维度一样。

1,
  1. =MATCH(DList,DList,0)
  1. {1;2;3;4;5;6;3;4;4;3;2;6}
说明表示:字符串在序列中第一次出现时的相对位置

2,
  1. =MATCH(DList,E$1:E3,0)
  1. {#N/A;#N/A;2;3;#N/A;#N/A;2;3;3;2;#N/A;#N/A}
说明表示:查询字符串数组在序列中首次出现的相对位置,没有找到则报错,可用于去重复

3,
  1. =MATCH(DList,DList,0)=ROW(DList)-1
  1. {1;1;1;1;1;1;0;0;0;0;0;0}
说明表示:序列中的值是否为重复值,第一次出现记为1,重复出现记为0

最后,看了这么多,总得有点自己的想法,结合Gvntw和Mike的算法得出
  1. =INDEX(A:A,IF(ROW(1:1)>SUM(N(MATCH(DList,DList,0)=ROW(DList)-1)),4^8,MOD(LARGE(COUNTIF(DList,DList)*(MATCH(DList,DList,0)=ROW(DList)-1)*10^8+(COUNTIF(DList,">="&DList)-SUM(COUNTIF(DList,I$1:I1)))*10^5+ROW(DList),ROW(1:1)),10^5)))&""
对Chandoo先生的公式,稍微改动,
  1. =IFERROR(INDEX(DList,MATCH(MIN(MODE.MULT(IF(COUNTIF(J$1:J1,DList)=0,(COUNTIF(DList,"<"&DList)+1)*{1,1}))),COUNTIF(DList,"<"&DList)+1,0)),"")
欢迎大家交流自己的公式想法。

附件:

SUF.rar



2楼
xyf2210
学习
3楼
嘉昆2011
谢谢支持,多指正
4楼
houtian23
厉害啊
一看到长公式我就发晕了
琢磨着还是VBA好一点
5楼
嘉昆2011
是的哟,数组+字典就不错。
6楼
shorling
公式好长啊~~有点晕的感觉。
7楼
sharkzhou
2003版打开,公式不可啊
8楼
yangkeyuan
学习了!

免责声明

有感于原ExcelTip.Net留存知识的价值及部分知识具有的时间限定性因素, 经与ExcelTip.Net站长Apolloh商议并征得其同意, 现将原属ExcelTip.Net的知识帖采集资料于本站点进行展示, 供有需要的人士查询使用,也慰缅曾经的论坛时代。 所示各个帖子的原作者如对版权有异议, 可与本人沟通提出,或于本站点留言,我们会尽快处理。 在此,感谢ExcelTip.Net站长Apolloh的支持,感谢本站点所有人**绿色风(QQ:79664738)**的支持与奉献,特此鸣谢!
------本人网名**KevinChengCW(QQ:1210618015)**原ExcelTip.Net总版主之一

评论列表
sitemap