<% ' +---------------------------------------------------------------------- ' | POPASP [ ASP MVC ] ' +---------------------------------------------------------------------- ' | Copyright (c) 2016 http://popasp.com All rights reserved. ' +---------------------------------------------------------------------- ' | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) ' +---------------------------------------------------------------------- ' | Author: popasp <1737025626@qq.com> ' +---------------------------------------------------------------------- Class POPASP_DICTIONARY Public sortByNumeric,sortByDate '从数据库中取出的数据为二维Dictionary对象,可以将其转化为Table表格 public Property Get Table( ByRef dict ) Table = P_("POPASP_HTML").Table( dict,"","","" ) End Property '从数据库中取出的数据为二维Dictionary对象,可以将其转化为Excel表格 '1) 文本(text,t):vnd.ms-excel.numberformat:@ '2) 日期(date,d):vnd.ms-excel.numberformat:yyyy/mm/dd hh:mm:ss '3) 数字(number,n):vnd.ms-excel.numberformat:#,##0.00 '4) 货币(currency,c,¥,$):vnd.ms-excel.numberformat:¥#,##0.00 '5) 百分比(percent,p):vnd.ms-excel.numberformat: #0.00% 'style为数组,分别对应各字段的类型,默认空字符串""为文本类型 public sub Excel( ByRef dict , ByVal style , ByVal filename ) Call C_( Array( "SHOW_PAGE_TRACE" , 0 ) ) filename = POP_MVC.String.rtrim( filename,".xls" ) filename = POP_MVC.String.rtrim( filename,".xlsx" ) '如果要调试,请注释掉下面两行代码 Response.ContentType = "application/excel" Response.AddHeader "Content-Disposition", "attachment;filename="""& filename &".xls""" dim html,i,k1,k2,item,j,temp 'i用来计算行数,j计算列数 html = "" & VbCrLf html = html & "" & VbCrLf html = html & "" & VbCrLf html = html & "" & VbCrLf html = html & "" & VbCrLf html = html & "" & VbCrLf html = html & "" i = 0 for each k1 in dict j = 0 set item = dict(k1) if i = 0 then html = html & VbCrLf & vbTab & "" html = html & VbCrLf & vbTab & vbTab for each k2 in item html = html & "" next html = html & VbCrLf & vbTab & "" if not isArray(style) then style = split( style,"," ) end if for j = 0 to ubound( style ) if style(j) = "" then style(j) = "number" end if next if item.count > ubound( style ) + 1 then '如果类型数组中的元素个数小于字段个数,则用数字类型代替 temp = style( ubound(style) ) for j = item.count - 1 to ubound( style ) step -1 POP_MVC.Arr.Push style,temp next end if end if html = html & VbCrLf & vbTab & "" html = html & VbCrLf & vbTab & vbTab j = 0 for each k2 in item select case LCase(style(j)) case "text","t" html = html & "" case "date","d" html = html & "" case "number","n" html = html & "" case "currency","c","¥" html = html & "" case "currency","c","$" html = html & "" case "percent","p" html = html & "" End Select j = j + 1 next html = html & VbCrLf & vbTab & "" i = i + 1 next html = html & VbCrLf & "
" & k2 & "
" & item(k2) & "" & item(k2) & "" & item(k2) & "" & item(k2) & "" & item(k2) & "" & item(k2) & "
" html = html & VbCrLf & "" html = html & VbCrLf & "" set dict = nothing Response.write html End sub Private Sub Class_Initialize sortByNumeric = True sortByDate = True End Sub '''''''''''''修改函数 '向Dictionary对象尾部添加一个键值对 Sub Push(ByRef dict, ByRef key, ByRef val) if typename(dict) <> "Dictionary" then set dict = Create() if dict.Exists(key) then dict.remove(key) end if if key = "" then '如果键名为空,则以当前的个数为键名 dict.add dict.count,val else dict.add key,val end if End Sub '向Dictionary对象头部添加一个键值对,如果dict为 var("key") 类型则不能添加 Sub Unshift(ByRef dict,ByVal key,ByRef val) if typename(dict) <> "Dictionary" then set dict = Create() dim temp set temp = Create() if key = "" then '如果键名为空,则以当前的个数为键名 key = dict.count end if temp.add key,val if typename(dict) <> "Dictionary" then set dict = Create() set dict = Merge(temp,dict) end sub '向Dictionary对象的某个键名前面插入一个键值对 '如果向不存在的键名前面插入键值对,则会追加到对象尾部 Sub InsertBefore( ByRef dict, ByRef beforeKey, ByRef key,ByRef val) if typename(dict) <> "Dictionary" then set dict = Create() dim temp,i if Not dict.Exists( beforeKey ) Then Push dict,key,val Exit Sub end if if dict.Exists( key ) Then dict.Remove(key) for each i in dict if i = beforeKey then Push temp,key,val end if Push temp,i,dict.item(i) next set dict = temp set temp = nothing End Sub '向Dictionary对象的某个键名后面插入一个键值对 '如果向不存在的键名前面插入键值对,则会追加到对象尾部 Sub InsertAfter( ByRef dict, ByRef afterKey, ByRef key,ByRef val) if typename(dict) <> "Dictionary" then set dict = Create() dim temp,i if Not dict.Exists( afterKey ) Then Push dict,key,val Exit Sub end if if dict.Exists( key ) Then dict.Remove(key) for each i in dict Push temp,i,dict.item(i) if i = afterKey then Push temp,key,val end if next set dict = temp set temp = nothing End Sub '从Dictionary对象中删除最后一个键值对,并以数组形式返回 Function Pop(ByRef dict) dim key,arr,i,cnt if typename(dict) <> "Dictionary" then Exit Function cnt = dict.Count if cnt = 0 then Exit Function i = 0 for each key in dict i = i + 1 if i = cnt then POP_MVC.Arr.push arr,key POP_MVC.Arr.push arr,dict(key) dict.remove(key) end if next Pop = arr End Function '从Dictionary对象中删除第一个键值对,并以数组形式返回 Function Shift(ByRef dict) dim key,arr for each key in dict POP_MVC.Arr.push arr,key POP_MVC.Arr.push arr,dict(key) dict.remove(key) exit for next shift = arr End Function ' 将Dictionary对象两个键名对应的值进行交换 Sub vswap( ByRef dict,ByVal key1,ByVal key2 ) dim temp if Not dict.Exists( key1 ) OR Not dict.Exists( key2 ) Then Exit Sub if isObject(dict(key1)) then set temp = dict(key1) else temp = dict(key1) call Edit( dict,key1,dict(key2) ) call Edit( dict,key2,temp ) if isObject(temp) then set temp = nothing End sub ' 将Dictionary对象两个键名进行交换 Sub kswap( ByRef dict,ByVal key1,ByVal key2 ) dim k1,k2,key key = "__POPASP_|/YouShouldNotGuess\|__POPASP_" k1 = key1 : k2 = key2 dict.key(key2) = key : dict.key(key1) = k2 : dict.key(key) = k1 End sub ' 将Dictionary对象的两个键值对进行交换,相当于两个键值对交换了位置 Sub kvswap( ByRef dict,ByVal key1,ByVal key2 ) call kswap( dict,key1,key2 ) call vswap( dict,key1,key2 ) End Sub ' 修改一对键值对,如果存在则修改,否则向尾部添加 Sub Edit(ByRef dict,ByVal key, ByRef val) if typename(dict) <> "Dictionary" then set dict = Create() if dict.Exists(key) Then if isObject(val) Then dim stype : stype = typename( val ) if stype = "Field" then '如果类型为Field字段类型 if typename( val.value ) = "Byte()" then set dict(key) = val.value else dict(key) = val.value end if else set dict(key) = val end if Else dict(key) = val End If else dict.add key,val end if End Sub '判断dict中是否存在某个键值链 '比如POP_MVC.KeyExists( dict, "a.b.c" , "." ) Function KeyExists( ByVal dict, ByVal keys , ByVal sep ) if typename(dict) <> "Dictionary" then KeyExists = False : Exit Function end if dim arr,i,temp,cnt arr = split( keys , sep ) cnt = ubound( arr ) for i = 0 to cnt if dict.exists( arr(i) ) then if i <> cnt then if typename( dict(arr(i) ) ) = "Dictionary" then set dict = dict( arr(i) ) else KeyExists = False : Exit Function end if end if else KeyExists = False : Exit Function end if next KeyExists = true End Function '''''''''''查找函数 ' 判断某个值是否存在于数组中,返回True或者False Function Exists( ByRef dict, ByRef val ) Exists = (Not isEmpty( Search(dict,val) )) End Function ' 在dict中搜索find,如果存在则返回键名,否则返回Empty Function Search( ByRef dict, ByRef val ) dim key for each key in dict if POP_MVC.isScalar( dict(key) ) AND dict(key) = val Then Search = key Exit Function End If next End Function '''''''''''数组函数 ' 将键名联接起来,如果只提供一个参数,则默认分隔符为空字符"" ' 如果参数为数组,则第一个参数为Dictionary对象,第二个参数为delimiter Function KeyJoin( ByRef args ) dim delimiter,dict delimiter = "" if isArray(args) then if ubound( args ) > 0 then delimiter = CStr(args(1)) end if if isObject( args(0) ) then set dict = args(0) else dict = args(0) end if else set dict = args end if KeyJoin = "" if Typename( dict ) = "Dictionary" then KeyJoin = Join( dict.keys , delimiter ) end if end function ' 创建一个空对象 Function Create() set Create = D_ End Function ' 克隆一个对象 Function Clone( ByRef Dict ) on error resume next Dim newDict,key Set newDict = Create() For Each key in Dict if isObject ( Dict(key) ) Then newDict.Add key, Me.Clone(Dict(key)) Else newDict.Add key, Dict(key) End If Next newDict.CompareMode = Dict.CompareMode Set Clone = newDict set newDict = nothing Call L_("POPASP_DICTIONARY.Clone") End Function ' 将值连接起来,如果只提供一个参数,则默认分隔符为空字符"" ' 如果参数为数组,则第一个参数为Dictionary对象,第二个参数为delimiter Function ItemJoin( ByRef args ) dim delimiter,dict delimiter = "" if isArray(args) then if ubound( args ) > 0 then delimiter = CStr(args(1)) end if if isObject( args(0) ) then set dict = args(0) else dict = args(0) end if else set dict = args end if ItemJoin = "" if Typename( dict ) = "Dictionary" then ItemJoin = Join( dict.items , delimiter ) end if end function ' 合并两个对象 ' 类似于PHP中的 array_merge,如果两个对象中同时存在某键,后者覆盖前者 Function Merge( ByRef dict1,ByRef dict2 ) dim key,dict set dict = Me.Clone(dict1) For Each key in dict2 Me.Edit dict,key,dict2(key) Next set Merge = dict set dict = nothing End Function ' 移除dict中重复的值(不能有对象)并将剩余的值返回一个数组(原dict不动) Function Unique( ByRef dict ) Unique = POP_MVC.Array.Unique( dict.Items ) End Function '用回调函数迭代地将dict简化为单一的值 Function Reduce( ByRef dict,ByRef func,ByRef initial ) Reduce = POP_MVC.Array.Reduce( dict.items,func,initial ) End Function '计算dict中所有值的乘积 Function Product( ByRef dict ) Product = POP_MVC.Array.Product( dict.items ) End Function '''''''''''过滤函数 '用回调函数过滤数组中的单元 Function [Filter]( Byref dict, Byref callback ) dim bool,ret,key for each key in dict Execute "bool = " & callback & "( key, dict(key) )" if bool then Push ret,key,dict(key) end if next if isObject( ret ) Then set [Filter] = ret else set [Filter] = Create() end if End Function ''''''''''''集合函数 ' 计算对象的差集 ' 类似于PHP中的 array_diff_key,返回一个对象,该对象包括了所有在 dict1 中但是不在 dict2 中键名的值。注意比较的是键名。 Function Diff ( ByRef dict1,ByRef dict2 ) dim key set dict = Clone(dict1) for each key in dict2 if dict.Exists( key ) then dict.remove(key) end if next set Diff = dict set dict = nothing End Function ' 计算对象的交集 ' 类似于PHP中的 array_intersect_key,返回一个对象,该对象包括了所有在 dict1 中同时存在于 dict2 中键名的值。注意比较的是键名。 Function Intersect ( ByRef dict1,ByRef dict2 ) on error resume next dim key set dict = Clone(dict1) for each key in dict if Not dict2.Exists( key ) then dict.remove(key) end if next set Intersect = dict set dict = nothing End Function ' 用src_dict中的数据更新dst_dict中也存在的键 Private Function Update ( ByRef dst_dict, ByRef src_dict ) dim key set dict = Clone(dst_dict) for each key in dict if src_dict.Exists(key) Then Edit dict,key,src_dict(key) End If next Set Update = dict set dict = nothing End Function ''''''''''dict排序函数,全部是在dict自身上进行操作'''''''''' ' 对dict按照字符串值正向排序 Sub sort( ByRef dict ) call AscSortByFunc( dict , "POP_MVC.String.cmp") End Sub ' 对dict按照字符串值逆向排序 Sub rsort( ByRef dict ) call DescSortByFunc( dict , "POP_MVC.String.cmp") End Sub ' 对dict按照键名正向排序 Sub ksort( ByRef dict ) call AscKeySortByFunc( dict , "POP_MVC.String.cmp") End Sub ' 对dict按照键名逆向排序 Sub krsort( ByRef dict ) call DescKeySortByFunc( dict , "POP_MVC.String.cmp") End Sub ' 对dict按照字符串值正向排序,并且忽略大小写 Sub casesort( ByRef dict ) call AscSortByFunc( dict , "POP_MVC.String.casecmp") End Sub ' 对dict按照字符串值逆向排序,并且忽略大小写 Sub casersort( ByRef dict ) call DescSortByFunc( dict , "POP_MVC.String.casecmp") End Sub ' 对dict按照键名正向排序,并且忽略大小写 Sub caseksort( ByRef dict ) call AscKeySortByFunc( dict , "POP_MVC.String.casecmp") End Sub ' 对dict按照键名逆向排序,并且忽略大小写 Sub casekrsort( ByRef dict ) call DescKeySortByFunc( dict , "POP_MVC.String.casecmp") End Sub ' 用“自然排序”算法按照字符串值正向排序 Sub natsort( ByRef dict ) call AscSortByFunc( dict , "POP_MVC.String.natcmp") End Sub ' 用“自然排序”算法按照字符串值逆向排序 Sub natrsort( ByRef dict ) call DescSortByFunc( dict , "POP_MVC.String.natcmp") End Sub ' 用“自然排序”算法按照键名正向排序 Sub natksort( ByRef dict ) call AscKeySortByFunc( dict , "POP_MVC.String.natcmp") End Sub ' 用“自然排序”算法按照键名逆向排序 Sub natkrsort( ByRef dict ) call DescKeySortByFunc( dict , "POP_MVC.String.natcmp") End Sub ' 用“自然排序”算法按照字符串值正向排序 ,并且忽略大小写 Sub casenatsort( ByRef dict ) call AscSortByFunc( dict , "POP_MVC.String.casenatcmp") End Sub ' 用“自然排序”算法按照字符串值逆向排序 ,并且忽略大小写 Sub casenatrsort( ByRef dict ) call DescSortByFunc( dict , "POP_MVC.String.casenatcmp") End Sub ' 用“自然排序”算法按照键名正向排序 ,并且忽略大小写 Sub casenatksort( ByRef dict ) call AscKeySortByFunc( dict , "POP_MVC.String.casenatcmp") End Sub ' 用“自然排序”算法按照键名逆向排序 ,并且忽略大小写 Sub casenatkrsort( ByRef dict ) call DescKeySortByFunc( dict , "POP_MVC.String.casenatcmp") End Sub '按用户自定义的比较函数根据值进行排序 Sub usort( ByRef dict,ByRef funcComp ) dim i,j,cnt,bool,arr arr = dict.keys cnt = ubound(arr) for i = 0 to cnt-1 for j = i+1 to cnt Execute "bool = " & funcComp & "( dict(arr(i)),dict(arr(j)) )" if bool > 0 then call kvswap(dict, arr(i),arr(j) ) call POP_MVC.Array.swap( arr,i,j ) end if next next End Sub '使用用户自定义的比较函数根据键名进行排序 Sub uksort( ByRef dict,ByRef funcComp ) dim i,j,cnt,bool,arr arr = dict.keys cnt = ubound(arr) for i = 0 to cnt-1 for j = i+1 to cnt Execute "bool = " & funcComp & "( arr(i),arr(j) )" if bool > 0 then call kvswap(dict, arr(i),arr(j) ) call POP_MVC.Array.swap( arr,i,j ) end if next next End Sub '按自定义函数进行升序排序, Public Sub AscSortByFunc( ByRef dict , ByRef funcComp ) call sortByFunc( dict , funcComp,false ) End Sub '按自定义函数进行升序排序, Public Sub DescSortByFunc( ByRef dict , ByRef funcComp ) call sortByFunc( dict , funcComp,true ) End Sub '对dict按照键名正向排序 Public Sub AscKeySortByFunc( ByRef dict , ByRef funcComp ) call ksortByFunc( dict , funcComp,false ) End Sub '对dict按照键名逆向排序 Public Sub DescKeySortByFunc( ByRef dict , ByRef funcComp ) call ksortByFunc( dict , funcComp,true ) End Sub ''''''''''''''其他函数 '返回一个单元顺序相反的对象 Function Reverse ( ByRef dict ) dim key,newDict set newDict = Create() for each key in dict Unshift newDict,key,dict(key) next set Reverse = newDict set newDict = nothing End Function ' 保留键名将dict打乱 sub shuffle( ByRef dict ) dim keys keys = dict.keys call POP_MVC.Array.shuffle( keys ) set keys = POP_MVC.Array.toDict( keys ) set keys = Flip(keys) set dict = Merge( keys,dict ) set keys = nothing End Sub ' 交换对象中的键和值 Function Flip( ByRef dict ) set Flip = Combine( dict.items,dict.keys ) End Function '创建一个新对象,用一个数组的值作为其键名,另一个数组的值作为其值 ' 成功返回dict,否则返回Empty Function Combine( ByRef keys,ByRef items ) dim bk,bv,i,dict ' 有一个不是数组,都退出 if not isArray(keys) or not isArray(items) then Exit Function bk = ubound(keys) : bv = ubound(items) ' 两者长度不同,也退出 if bk <> bv or bk = 0 or bv = 0 then Exit Function set dict = Create() for i = lbound(keys) to bk dict.add CStr(keys(i)),items(i) next set Combine = dict set dict = nothing End Function '将回调函数作用到给定对象的单元上,并返回一个新对象,键名保留不变 Function Map( ByRef dict,ByRef callback ) dim ret,key for each key in dict Execute "Me.Push ret,key," & callback & "(dict(key))" next set Map = ret End Function '按字符串值对dict使用funcComp进行排序 'isR是否为逆向,正向false,逆向true Private Sub sortByFunc( ByRef dict , ByRef funcComp, ByRef isR ) dim i,j,cnt,bool,arr arr = dict.keys cnt = ubound(arr) for i = 0 to cnt-1 for j = i+1 to cnt bool = false if Not is_empty(sortByDate) And isDate( dict( arr(i) ) ) And isDate( dict( arr(j) ) ) Then bool = ( DateDiff("s",dict(arr(j)),dict( arr(i) )) > 0 ) elseif Not is_empty(sortByNumeric) And isNumeric( dict( arr(i) ) ) And isNumeric( dict( arr(j) ) ) Then bool = ( dict(arr(i)) > dict(arr(j)) ) else Execute "bool = ( " & funcComp & "( dict(arr(i)),dict(arr(j)) )>0 )" end if if (not isR and bool) OR (isR and not bool) then call kvswap(dict, arr(i),arr(j) ) call POP_MVC.Array.swap( arr,i,j ) end if next next End Sub '按键名对dict使用funcComp进行排序 'isR是否为逆向,正向false,逆向true Private Sub ksortByFunc( ByRef dict , ByRef funcComp, ByRef isR ) dim i,j,cnt,bool,arr arr = dict.keys cnt = ubound(arr) for i = 0 to cnt-1 for j = i+1 to cnt bool = false if Not is_empty(sortByDate) And isDate( arr(i) ) And isDate( arr(j) ) Then bool = ( DateDiff("s",arr(j),arr(i)) > 0 ) elseif Not is_empty(sortByNumeric) And isNumeric( arr(i) ) And isNumeric( arr(j) ) Then bool = ( arr(i) > arr(j) ) else Execute "bool = ( " & funcComp & "( arr(i),arr(j) )>0 )" end if if (not isR and bool) OR (isR and not bool) then call kvswap(dict, arr(i),arr(j) ) call POP_MVC.Array.swap( arr,i,j ) end if next next End Sub End Class %>