鸟食轩

 Microsoft .NET[C#] MVP 2003
随笔 - 429, 文章 - 235, 评论 - 5529, 引用 - 356
数据加载中……

按阅读习惯来高效排列字符串的脚本

    对于字符串的排序,我们知道是比较相同index位置的字符的值来进行的。这样的排序有个问题,就是当被排序的字符串的内容是有数字顺序的,而且还不等长就比较的郁闷了。我们在xp以前的操作系统的资源管理器里,就会常常看到这样的文件名序列:

    x1, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19,x2x20, x21, x22...

    而我们的阅读习惯因该是这样的:

    x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17...

    如果是排列数字,按这种阅读习惯是理所当然的事情。可是对于字符串似乎就变得有些麻烦了,对于JScript脚本,系统提供了Array.sort()方法,可以高效的排列字符串。可是美中不足的是这个方法排序后的结果就是上面的第一种情况,完全不符合我们的阅读习惯:(。

    于是我们考虑使用分段排序的方式解决这个问题,代码如下:

function SortStringArray(ary)
{
    
var args = [];
    
var len = 0 ;
    
for ( var i = 0 ; i < ary.length ; ++ i )
    
{
        len 
= ary[i].length;
        
// len = new String(i).valueOf().length;
        if ( ! args[len] )
        
{
            args[len] 
= [];
        }

        args[len].push(ary[i]);
    }

    
var sortedArray = [];
    
for ( var j = 0 ; j <= args.length ; ++ j )
    
{
        
if ( args[j] )
        
{
            args[j].sort();
            sortedArray 
= sortedArray.concat(args[j]);
        }

    }

    
return sortedArray;
}

    由于使用了Array.sort()方法,排序效率非常高。10,000个字符串节点按阅读习惯排序所花的时间是281ms! 测试代码如下:

var ary = [];
var count = 10000 ;
for ( var i = 0 ; i < count ; ++i )
{
    
var item = 'xxxxxxxxx' + (count-i);
    ary.push(item);
}

ary.sort();
dtBegin 
= new Date();
ary 
= SortStringArray(ary);
alert(
new Date()-dtBegin); 


    后话:如果我们已知被排序的字符串是数字顺序的,那么用我们的SortStringArray()排序就行了,但是要去识别那些字符串是可以按数字顺序排列的,我想了想好像还很困难。看看下面这个xp的资源管理器的示例就清楚了:
    XP.Explorer.Sort.png
    红框里的文件的文件名就是没有数字顺序的,而xp的资源管理器就按普通的字符排序规则将其排序了。当然几十个百来个条目要判断出来还是很容易的,可是如果是好几千上万的条目,要找出有数字顺序的条目就比较的郁闷了。
 

posted on 2006-03-24 15:15 birdshome 阅读(1603) 评论(9)  编辑 收藏 网摘 所属分类: Jscript&Dhtml开发

评论

#1楼   回复  引用    

这是个错误的例子。
我们来看看这行代码会有什么运行结果:

alert( 'xxxxxxxxx' + 1 - 1)

错误的原因是+、-运算是左结合的, 'xxxxxxxxx' + 1 - 1= ('xxxxxxxxx' + 1) - 1 = NaN

正确的写法是

var item = 'xxxxxxxxx' + (count - i);
2006-04-08 17:59 | emu[未注册用户]

#2楼   回复  引用    

修正了上面的bug之后,楼主的排序算法依然很搞笑:

function SortStringArray(ary)
{
var args = [];
var len = 0 ;
for ( var i = 0 ; i < ary.length ; ++ i )
{
len = new String(i).valueOf().length;
if ( ! args[len] )
{
args[len] = [];
}
args[len].push(i);
}
var sortedArray = [];
for ( var j = 0 ; j <= args.length ; ++ j )
{
if ( args[j] )
{
args[j].sort();
sortedArray = sortedArray.concat(args[j]);
}
}
return sortedArray;
}

var ary = [];
var count = 10 ;
for ( var i = 0 ; i < count ; ++ i ){
var item = 'xxxxxxxxx' + ( count - i);
ary.push(item);
}
alert(ary)
ary = SortStringArray(ary);
alert(ary)

这是我们想要的结果吗?
2006-04-08 18:01 | emu[未注册用户]

#3楼   回复  引用    

其实正确的做法很简单:

var n=100;
var ary=new Array(n)
for(var i=0;i<n;i++) ary[i]="xxx"+(n-i);
ary.sort(function(a,b){return a.replace(/\D/g,"")-b.replace(/\D/g,"")})
alert(ary)
2006-04-08 18:05 | emu[未注册用户]

#4楼   回复  引用    

如果要快一点,也许可以这样:

var n=1000;

var ary=new Array(n)

for(var i=0;i<n;i++) ary[i]="xxx"+(n-i);

function SortStringArray(ary){
var n =ary.length;
var t = new Array(n);
for(var i=0;i<n;i++)
t[i] = [ary[i].replace(/\D/g,"")-0,i];
t.sort(function(a,b){return a[0]-b[0]});
var result = new Array(n)
for(var i=0;i<n;i++) result[i]=ary[t[i][1]];
return result;
}

var d = new Date();
var ar = SortStringArray(ary);
alert(new Date()-d)
2006-04-08 18:23 | emu[未注册用户]

#5楼[楼主]   回复  引用  查看    

@emu
那个测试示例确实写错了,寒一个-_-!

至于SortStringArray(ary)方法,由于最开始一直用的1, 2, 3, ... , 10, 11, ... 这样的字符串来测试的,没想到又写错了两句话,没有发现:(
len = new String(i).valueOf().length;
因该是:len = ary[i].length; // 使用new String()是怕传入的本身就是数字
args[len].push(i);
这句也应该是:args[len].push(ary[i]);

btw: 之所以没有考虑字符串整理,是出于效率考虑的。再次感谢指出文中失误
2006-04-08 18:29 | birdshome      

#6楼   回复  引用    

修正了楼主的算法后,发现分治法确实还是优势很大的,关键是避免了sort过程每次都要调用比较算子的代价。

function SortStringArray(ary){
var args = [];
var len = 0 ;
for(var i=0;i<ary.length;i++){
var len = ary[i].length;
if(!args[len])args[len] = [];
args[len].push(ary[i]);
}
var sortedArray = [];
for(var i= 0 ; i<args.length ; i++ )
if(args[i]) sortedArray = sortedArray.concat(args[i].sort());
return sortedArray;
}

var ary = [];
var count = 10000 ;
for(var i=0;i<count;i++)
ary[i]='xxxxxxxxx' + ( count - i);
var d = new Date()
ary = SortStringArray(ary);
alert(new Date()-d)
2006-04-08 18:39 | emu[未注册用户]

#7楼[楼主]   回复  引用  查看    

@emu
恩,至少是数量级上的差别,你上面修改的那个1000个排序的算法,在10000个字符串时需要6s多。
2006-04-08 18:41 | birdshome      

#8楼   回复  引用    

其实上面我的两个排序的例子一样是错的,字符串的差异在比较中直接就忽略掉了呵呵。
2006-04-08 18:42 | emu[未注册用户]

#9楼[楼主]   回复  引用  查看    

@emu
晕倒!因为数据量太大了,我没敢输出出来看@_@,,,
2006-04-08 18:44 | birdshome      



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 357839





相关文章:

相关链接: