【问题标题】:Why is it faster to sort javascript strings than numbers?为什么对 javascript 字符串进行排序比对数字进行排序更快?
【发布时间】:2017-12-03 01:00:30
【问题描述】:

我正在调查一个先入之见,即在 javascript 中对字符串进行排序会比对整数进行排序要慢。这是基于我读过的东西(现在找不到),这似乎是错误的,它表明 javascript 将字符串存储为Array<Array<int>> 而不仅仅是Array<int>MDN documentation 似乎与此相矛盾:

JavaScript 的 String 类型用于表示文本数据。它是一组 16 位无符号整数值的“元素”。 String 中的每个元素在 String 中占据一个位置。第一个元素在索引 0 处,下一个在索引 1 处,依此类推。 String 的长度就是其中的元素个数。

如果我们将元素(数字或字符串)的“大小”定义为其文本表示的长度(因此size = String(x).length 用于数字元素或字符串元素),那么对于大小相同(一个数字和一个字符串),我期望字符串的排序等于或稍慢比排序数组,但是当我运行一个简单的测试(下面的代码)时,事实证明,字符串的排序速度大约是原来的两倍。

我想知道它是关于字符串和数字的,以及 javascript 如何进行排序,这使得字符串排序比数字排序更快。或许我有什么误解。

结果:

~/sandbox > node strings-vs-ints.js 10000 16
Sorting 10000 numbers of magnitude 10^16
Sorting 10000 strings of length 16
Numbers: 18
Strings: 9
~/sandbox > node strings-vs-ints.js 1000000 16
Sorting 1000000 numbers of magnitude 10^16
Sorting 1000000 strings of length 16
Numbers: 3418
Strings: 1529
~/sandbox > node strings-vs-ints.js 1000000 32
Sorting 1000000 numbers of magnitude 10^32
Sorting 1000000 strings of length 32
Numbers: 3634
Strings: 1474

来源:

"use strict";
const CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghjijklmnopqrstuvwxyz0123456789:.";

function generateString(L) {
    const chars = [];
    while(chars.length < L) {
        chars.push(CHARSET[Math.floor(Math.random() * CHARSET.length)]);
    }
    return chars.join("");
}

function generateNumber(L) {
    return Math.floor(Math.random() * Math.pow(10, (L - 1))) + Math.pow(10, L - 1);
}

function generateList(generator, L, N) {
    const elements = [];
    while(elements.length < N) {
        elements.push(generator.call(null, L));
    }
    return elements;
}

function now() {
    return Date.now();
}

function getTime(baseTime) {
    return now() - baseTime;
}

function main(count, size) {
    console.log(`Sorting ${count} numbers of magnitude 10^${size}`);
    const numbers = generateList(generateNumber, size, count);
    const numBaseTime = now();
    numbers.sort();
    const numTime = getTime(numBaseTime);

    console.log(`Sorting ${count} strings of length ${size}`);
    const strings = generateList(generateString, size, count);
    const strBaseTime = now();
    strings.sort();
    const strTime = getTime(strBaseTime);

    console.log(`Numbers: ${numTime}\nStrings: ${strTime}`);
}

main(process.argv[2], process.argv[3]);

【问题讨论】:

  • 字符串 - 无需查找重量。数字 - 您需要找到重量并根据该重量进行排序。就像考虑 "500", "1000"500, 1000 一样。前者是交换的,后者是对的。这只是我对为什么会这样的理解。它可能正确也可能不正确。
  • 请注意,10^32 大小的浮点数无论如何都将使用科学记数法进行字符串化。熵只有 64 位,无法得到任意长的字符串表示。
  • @Bergi 是对的,如果您不提供对 sort 函数的回调,那么它将继续进行默认排序,强制将要比较的值转换为字符串(如果它们还不是字符串类型)。
  • 好的,谢谢@Bergi。我会重新运行我的测试,看看这是否会显着改变。

标签: javascript arrays performance sorting primitive


【解决方案1】:

我正在调查一个先入之见,即在 javascript 中排序字符串会比排序整数慢。

没错,字符串比较的成本比数字比较高。

这是基于我读到的内容,其中指出 javascript 将字符串存储为 Array&lt;Array&lt;int&gt;&gt; 而不仅仅是 Array&lt;int&gt;。 MDN 文档似乎与此相矛盾。

是的,您阅读的内容似乎确实是错误的。字符串只是字符序列(每个字符都是 16 位值),因此它们通常存储为整数数组,或者更确切地说是pointers to them。不过,您的字符串数组确实可以被视为数组的数组。

当我运行一个简单的测试时,结果表明字符串的排序速度大约是原来的两倍。

您的代码的问题在于您将数字排序为字符串,它将每个数字转换为字符串然后进行比较。见How to sort an array of integers correctly。当你修复它时,请注意对比较函数的调用仍然对内置字符串比较有相当多的开销,所以如果你真的对不同类型的关系运算符(&lt;==&gt;)进行基准测试我希望数字表现更好。

【讨论】:

    猜你喜欢
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    • 2014-07-10
    • 2016-07-18
    • 1970-01-01
    相关资源
    最近更新 更多