数组排序,字符串math,replace练习

1. 关于数组排序

    排序一直是程序设计中的热门话题。在js中,数组有个sort()方法。在不传参数默认情况下,数组的sort()方法原理是:对数每项调用toString()方法,比较字符串按升序排序数组。看下面的例子。

var arrA = [null, undefined, 3, 2, 5, 21, {toString:function() {
    return 1;
}, p:'hello'}];
var arrB = [undefined, null, 3, 2, 5, 21,{toString:function() {
    return 1;
}, p: 'hello'}];    
var arrC = [null, undefined, 3, 2, 21, {toString:function() {
    return 1;
}, p:'hello'},
{a:1},
{toString:function(){return 'p'}},
{toString:function(){return 'oa'}},
{toString:function(){return 'p'}},
{toString:function(){return 'v'}}, 'u', 'v', 'nukk','nulk'
];

arrA.sort();//结果是:[Object, 2, 21, 3, 5, null, undefined]
arrB.sort();//结果是:[Object, 2, 21, 3, 5, null, undefined]
arrA.sort()[0].p;//hello
arrC.sort();

上面的例子说明:

a. sort()方法不传比较函数时,的确是对每项调用了toString()方法[对null应该是使用String(null)]转换成字符串再进行升序排序的

b. undefined不会参与排序,直接放最后面

当要使用其它标准对数组进行排序时,就要传入一个比较函数作为参数。原理及执行过程没有弄清楚(有知道的请告诉下),但得到如下结论:

var arrD = [3, 5, 1, 8, 10];

console.log(arrD.sort(compare));

function compare(v1, v2) {
    var a = v1;
    var b = v2;
    console.log('v1='+v1 + '||'+ 'v2='+v2);
    //return v1 - v2; //升序
    //return v2 - v1;//降序
    //return -1;  //原样输出
    //return 0; //原样输出
    //return 1; //反顺输出
}

下面是一个实际Demo:

/**
 * 为数组实现一个排序方法,能够num、string、date、character和object的排序,
 * 对object类型排序时,按照某个属性排序。只考虑数组中存放都是相同类型的数据
 * @param {Boolean} order 为true表示升序,false表示降序
 * @param {String} key 对象的键值
 */
Array.prototype.sameTypeSort = function(order, key) {
    var type = type(this[0]);
    var ret = [], i = 0, temp, tempArr = [];
    order = order ? true : false;
    switch(type) {
        case 'string':
            ret = this.sort();//升序
            break;
        case 'number':
            ret = this.sort(ascending);
            break;
        case 'date':
            while(temp = this[i]) {
                tempArr.push(temp.getTime());
                i++;
            }
            tempArr.sort(ascending);
            break;
        default :
            while(i < this.length) {
                tempArr.push(this[i][key]);
                i++;
            }
            tempArr = tempArr.sameTypeSort(true);
    }


    //如果是时间,对象还要将还原成排序前的值
    if(type === 'date') {
        i = 0;
        while(temp = tempArr[i]) {
            ret.push(new Date(temp));
            i++;
        }
    }

    if(type === 'object') {
        i = 0;
        while(temp = tempArr[i]) {
            for(var start = 0, curObj, value; curObj = this[start]; start++) {
                value = curObj[key];
                if(value === temp) {
                    ret.push(curObj);
                    break;
                }
            }
            i++;
        }
    }

    return order ? ret : ret.reverse();

    function type(target) {
        return ({}).toString.call(target).slice(8, -1).toLocaleLowerCase();
    }
    function ascending(v1, v2) {
        return v1 - v2;
    }
};

下面是通过的Qunit的测试代码:

test( "数值排序", function() {
    var arr = [1,11,2,22,3,33,-5,-55, 0];
    var upOrder = [-55, -5, 0, 1,2,3,11,22, 33];

    propEqual(arr.sameTypeSort(true), upOrder, 'pass');
    propEqual(arr.sameTypeSort(false), upOrder.reverse(), 'pass');
});

test( "字符串排序", function() {
    var arr = ['aa', 'ac', 'ab', 'bc', 'ba', 'acd'];
    var upOrder = ['aa', 'ab', 'ac', 'acd', 'ba', 'bc'];

    propEqual(arr.sameTypeSort(true), upOrder, 'pass');
    propEqual(arr.sameTypeSort(false), upOrder.reverse(), 'pass');
});

test( "时间排序", function() {
    var arr = [new Date('2014/06/16 0:0:0'), new Date('2014/06/12 0:0:0'), new Date('2014/06/14 0:0:0')];

    strictEqual(arr.sameTypeSort(true)[0].getTime(), arr[1].getTime());
    strictEqual(arr.sameTypeSort(false)[0].getTime(), arr[0].getTime());
});

test( "对象排序", function() {
    var arr = [
        {key:5, f: 'x'},
        {key:2, f:'y'},
        {key:6, f:'z'}
    ];

    strictEqual(arr.sameTypeSort(true, 'key')[0].f, 'y');
    strictEqual(arr.sameTypeSort(false, 'key')[0].f,'z');
    console.log(arr.sameTypeSort(true, 'key'));
    console.log(arr.sameTypeSort(false, 'key'));
});

2. match,replace函数练习

a. 价格千分

/**
 * 在整数部分对费用进行千分。一开始想用正则来做,但实现过程中发现各种问题,最后代码变成下面的样子了
 * @param {String} feeStr 有效的费用数值字符串
 * @returns {String} 进行了千分格式化后的字符串
 */
function splitFee(feeStr) {
    var ret, leftCtx, rightCtx;

    ponintPos = feeStr.indexOf('.');
    if(ponintPos !== -1) {
        leftCtx = feeStr.substring(0, ponintPos);
        rightCtx = feeStr.substring(ponintPos+1);
    } else {
        leftCtx = feeStr;
        rightCtx = '';
    }

    /*match = feeStr.match(/\./);
    leftCtx = RegExp.leftContext;//整数部分
    rightCtx = RegExp.rightContext;  使用正则会有一个Bug,若后面match匹配失败,后面的rightCtx始终会保存前次匹配的值*/
    leftCtx = leftCtx ? leftCtx : feeStr;
    rightCtx = rightCtx ? '.'+rightCtx : '';

    ret = (leftCtx.split('').reverse().join('').replace(/(\d{3})/g, function(m, ms, offset, targetStr) {
        return m + ','
    }).split('').reverse().join('')+rightCtx).replace(/^\,/,'');

    return ret;
}

通过的Qunit测试代码

test( "replace, match练习:数值字符串千分", function() {
    //对整数部分进行千分
    var fee1 = '1747136.51';
    var fee2 = '277136.52';
    var fee3 = '37136.53';
    var fee4 = '47136';
    var fee5 = '136';

    strictEqual(splitFee(fee1), '1,747,136.51');
    strictEqual(splitFee(fee2), '277,136.52');
    strictEqual(splitFee(fee3), '37,136.53');
    strictEqual(splitFee(fee4), '47,136');
    strictEqual(splitFee(fee5), '136');
});

b. 交换包含两个单词的字符串

/**
 * 交换单词字符串中的两个单词
 * @param str
 * @returns {String}
 */
function swapTwoWords(str) {
    return str.replace(/(\w+)\s(\w+)/, '$2 $1');
    //return str.split(' ').reverse().join(' '); 使用数组
}

//Qunit测试
test( "replace练习:交换单词", function() {
    var str = 'hello world';

    strictEqual(swapTwoWords(str), 'world hello');
});

c. 字符串模板替换方法

/**
 * 字符串模板替换方法
 * @param {String} str
 * @param {Object} obj
 */
function format(str, obj) {
    return str.replace(/({\w+})/gm, function(m, ms, offset, targetStr) {
        return obj[m.substring(1, m.length - 1)];
    });
}

//Qunit测试
test( "字符串模板format方法", function() {
    var str = '<div>{id}</div></div>{name}</div>';

    strictEqual(format(str, {id:100, name:'xyz', address:'cd'}), '<div>100</div></div>xyz</div>');
});
posted @ 2014-06-15 08:46  jagus720  阅读(294)  评论(0编辑  收藏  举报