Sort array of objects with dots, letters, numbers. I was able to sort by numbers, but mixed values are difficult. Not sure if possible to do it right

前端 未结 2 419
梦谈多话
梦谈多话 2021-01-17 20:10

I tried the typical sort function and checked if item is string. But I get a very strange output. Tried multiple different approaches.

 var arr = [{section:          


        
2条回答
  •  一生所求
    2021-01-17 20:37

    You could split the string and use sorting with map, while comparing each element of the one with each element of the other one. if both elements are numbers, take the difference, otherwise return the result of localeCompare.

    Bonus: Sort with roman numbers.

    function customSort(data, key, order) {
    
        function isNumber(v) {
            return (+v).toString() === v;
        }
    
        function isRoman(s) {
            // http://stackoverflow.com/a/267405/1447675
            return /^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/i.test(s);
        }
    
        function parseRoman(s) {
            var val = { M: 1000, D: 500, C: 100, L: 50, X: 10, V: 5, I: 1 };
            return s.toUpperCase().split('').reduce(function (r, a, i, aa) {
                return val[a] < val[aa[i + 1]] ? r - val[a] : r + val[a];
            }, 0);
        }
    
        var sort = {
                asc: function (a, b) {
                    var i = 0,
                        l = Math.min(a.value.length, b.value.length);
    
                    while (i < l && a.value[i] === b.value[i]) {
                        i++;
                    }
                    if (i === l) {
                        return a.value.length - b.value.length;
                    }
                    if (isNumber(a.value[i]) && isNumber(b.value[i])) {
                        return a.value[i] - b.value[i];
                    }
                    if (isRoman(a.value[i]) && isRoman(b.value[i])) {
                        return parseRoman(a.value[i]) - parseRoman(b.value[i]);
                    }
                    return a.value[i].localeCompare(b.value[i]);
                },
                desc: function (a, b) {
                    return sort.asc(b, a);
                }
            },
            mapped = data.map(function (el, i) {
                var string = el[key].replace(/\d(?=[a-z])|[a-z](?=\.)/gi, '$&. .'),
                    regex = /(\d+)|([^0-9.]+)/g,
                    m,
                    parts = [];
    
                while ((m = regex.exec(string)) !== null) {
                    parts.push(m[0]);
                }
                return { index: i, value: parts, o: el, string: string };
            });
    
        mapped.sort(sort[order] || sort.asc);
        return mapped.map(function (el) {
            return data[el.index];
        });
    }
    
    var arr = [{ section: '12.2.a' }, { section: '12.2.b.viii' }, { section: '12.2.b.xi' }, { section: '12.2.b.x' }, { section: '12.2.b.ix' }, { section: '12.2.b.vii' }, { section: '12.2.b.vi' }, { section: '12.2.b.iv' }, { section: '12.2.b.v' }, { section: '12.2.b.ii' }, { section: '12.2.b.iii' }, { section: '12.2.b.i' }, { section: '12.2.b.iii' }, { section: '12.2.c' }, { section: '12' }, { section: '12A' }, { section: '12.3.b' }, { section: '12.3.c' }, { section: 'Q2' }, { section: 'Q32' }, { section: 'Q6' }, { section: 'Q5' }, { section: 'Q.10' }, { section: 'Q.1' }, { section: 'Q.2' }];
    
    console.log('sorted array asc', customSort(arr, 'section'));
    console.log('sorted array desc', customSort(arr, 'section', 'desc'));
    console.log('original array', arr);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

提交回复
热议问题