2016-07-28 103 views
0

我想对从文档中提取的某些段落号进行排序。Nodejs:对段落号进行排序

不幸的是,他们并不是真正的小数所以标准sort功能不起作用。例如,我想要以下结果:["3.1","3.2","3.11"]不是["3.1","3.11","3.2"](这是我从使用中得到的结果:http://www.w3schools.com/jsref/jsref_sort.asp)。

的数字也有小数数量不确定。例如,他们可能会出现如下:["1.i.a","1.i.b","1.i.c.A","1.i.c.B"]

在处理这个问题一段时间后,我认为最好的解决方案是将每个数字视为由'。'分隔的子字符串,并根据'最低'子字符串。

任何人都可以提出如何在JS做什么?

任何帮助深表感谢

+0

你永远不需要比较一个数字和一个字母,是正确的吗?例如,'3.4'和'3.a'永远不需要比较? – apsillers

+1

有些想法:你的子串是数字,在这种情况下,排序很简单,或者它们是字母。在这种情况下,您可以尝试执行查找表来对其进行编号转换。唯一的问题将是罗马数字('I','IV' ...),除非您找到一种方法可靠地将它们与简单字母区分开来。 – DrakaSAN

+0

@apsillers - 是的,这是正确的。所有的子字符串将是相同的类型。 – qts

回答

1

这是否适合您?如果需要,我可以提供更多解释。

"use strict" 
let index = ['3.1.a', '3.2', '3.11', '3.1.c', '3.2.z']; 

index.sort((a, b) => { 
    var aArr = a.split('.'), bArr = b.split('.') 

    for (var i = 0, aLength = aArr.length; i < aLength; i++) { 
    let aVal = aArr[i], bVal = bArr[i] 
    if (!isNaN(aVal)) aVal = Number(aVal) // convert substring into Number if it is a Number 
    if (!isNaN(bVal)) bVal = Number(bVal) 

    if (bVal === undefined) return 1 // b lower index 
    if (aVal === bVal) continue 

    return typeof(aVal) === "string" ? aVal.charCodeAt() - bVal.charCodeAt() : aVal - bVal; // for strings, works only if length == 1 
    } 

    return bArr[i] === undefined ? 0 : -1 // if b undefined, then both numbers are equal, otherwise a is shorter 
}) 

console.log(index) 
// outputs [ '3.1.a', '3.1.c', '3.2', '3.2.z', '3.11' ] 
+0

你能帮我理解这段代码吗?我一直在使用它几个星期,并发现它对罗马数字不能100%工作(例如'3.1.a.vi',3.1.a.iv')。另外,当我控制台登录输出,aVal - bVal返回字母'NaN' – qts

+0

你是对的,这里的代码不适用于字母。我可以为此添加一点修正。对于罗马数字,这是一个前卫的例子,因为没有办法区分它和普通字母。以下是我的建议:如果一个子字符串对应一个罗马数字,它将被视为一个罗马数字(例如,如果您有3.4.i,它将被转换为3.4.1)。你怎么看? – jonathanGB

+1

@qts我已经修复了答案,所以它可以正确使用字母。现在,它只会在子字符串只是一个字母时才起作用。这可以吗? – jonathanGB

0

一个不完整的,相当严格的方式做到这一点可能是这样的:

'use strict'; 

const async = require('async'); 

let index = ['3.1.a', '3.2', '3.11', '3.1.c', '3.2.z']; 

//'3.1.a' => ['3', '1', 'a'] 
function paragraphToSubstring(string, callback) { 
    async.map(string, (s, callback) => { 
     callback(null, s.split('.')); 
    }, (err, substrings) => { 
     callback(substrings); 
    }); 
} 

//['3', '1', 'a'] => [3, 1, 1] 
function substringToNumber(substrings) { 
    async.map(substrings, (e, callback) { 
     let i = parseInt(e); 
     //If e is a letter 
     if(isNaN(i)) { 
      //Take it's ASCII value 
      //If you need to support roman number, you'll have to make the check and transformation here 
      callback(null, e.charCodeAt(0)); 
     } else { 
      callback(null, i); 
     } 
    }) 
} 

function sort(paragraphs, callback) { 
    async.waterfall([ 
     //Convert everything in array 
     (callback) => { 
      async.map(paragraphs, (p, callback) => { 
       paragraphToSubstring(p, (s) => { 
        callback(null, s); 
       }); 
      }, (err, substrings) => { 
       callback(err, substrings) 
      }); 
     }, 
     //Convert everything in numbers 
     (substrings, callback) => { 
      async.map(substrings, (s, callback) => { 
       substringToNumber(s, (err, i) => { 
        callback(err, i); 
       }); 
      }, (err, numbers) => { 
       callback(err, numbers); 
      }); 
     } 
     //Sort 
     (numbers, callback) => { 
      callback(null, numbers.sort((a, b) => { 
       //Didn't found a way to support a undefinite number of element, settled on 3 
       let s1 = a[0] - b[0], 
        s2 = a[1] - b[1], 
        s3 = a[2] - b[2]; 

       if(s1) { 
        return s1; 
       } 
       if(s2) { 
        return s2; 
       } 
       if(s3) { 
        return s3; 
       } 
      })); 
     } 
    ], (err, sorted) { 
     callback(err, sorted); 
    }); 
} 

有趣的练习做,我会回来以后有好转,当我还得有更多的工作时间。

+0

我认为这太过于浪费了haha – jonathanGB

+0

@jonathanGB:可能我没有考虑到性能,更多的是关于可读性和处理每一个可能的错误。 – DrakaSAN

+0

为什么是异步?这里没有I/O或ajax? – jonathanGB