【问题标题】:Javascript ES6 custom sort method not working all the timesJavascript ES6自定义排序方法并非一直有效
【发布时间】:2017-10-17 18:21:10
【问题描述】:

我想对我的 JSON 输出进行排序。

我为它创建了自己的排序方法,您可以在此处看到:

const sortAsc = (propertyName) => (a, b) => a[propertyName] === b[propertyName] ? 0 : a[propertyName] < b[propertyName] ? -1 : 1;
const sortDesc = (propertyName) => (a, b) => a[propertyName] === b[propertyName] ? 0 : a[propertyName] < b[propertyName] ? 1 : -1;

我这样称呼它:

asc(value) {
    this.result.sort(this.sortAsc(value));
}

它可以正常工作,但是当我对其进行排序时,它并不总是正确排序。

看看这个小 gif: https://gyazo.com/5f590f7c921eb1cb3bc4138f85c2162b

如您所见,它实际上不适用于 ID。它在Naam (荷兰语名称)上升序工作,但在降序时,它首先给出 2 个以 v 和 k 开头的名称。这是为什么呢?

好吧,如果这是难以解决的问题,那也不是问题。只要它可以对数字和字符串进行排序。

还有一点需要注意的是,我使用的是 Angular 4.4.4。我搜索了一个内置的 sort/orderBy 函数,但发现它不是内置的。但是,如果我可以使用 Angular 提供的任何东西来简化它,我会很乐意使用它!

编辑:

我的新方法:

sortAsc = (propertyName) => (a, b) => a[propertyName].localeCompare(b[propertyName]);

【问题讨论】:

  • 比较字符串时您可能想使用String#localeCompare。这还允许您配置小写/大写单词的排序方式。
  • vk 可能区分大小写。我在某些数据库上似乎有类似的问题,其中小写a 被认为是在大写Z 之后。也许尝试在你的比较函数中.toLower()
  • 看起来它工作得很好。默认情况下,字符串不等式使用 unicode 代码点(包括 ASCII),因此按降序排列,您有小写字母,然后是大写字母。
  • 这不是您的问题,但您绝对应该将 sortDesc 实现为 -1 * sortAsc(...) 而不是复制。
  • 请以 JSON 格式发布您的实际数据(或重现问题所需的数据子集)。一个 gif 是不够的。

标签: javascript angular sorting ecmascript-6


【解决方案1】:

您可以将String#localeCompare 与选项一起使用:

localeCompare() 方法返回一个数字,指示引用字符串是在排序顺序之前还是之后或与给定字符串相同。

新的localesoptions 参数允许应用程序指定应该使用其排序顺序的语言并自定义函数的行为。在忽略 localesoptions 参数的旧实现中,使用的语言环境和排序顺序完全取决于实现。

const sortAsc = propertyName => (a, b) =>
    a[propertyName].localeCompare(b[propertyName], undefined, { numeric: true, sensitivity: 'base' });


const sortDesc = (propertyName) => (a, b) =>
    -a[propertyName].localeCompare(b[propertyName], undefined, { numeric: true, sensitivity: 'base' });

【讨论】:

  • 很高兴知道这一点。我以前从未注意到这些选项。但是,您遇到了一个问题 - 数字没有 localeCompare 方法。使用 a[propertyName].toString().localeCompare() 似乎可以正常工作。
  • 对,字符串方法需要转换。
  • 我认为没有充分的理由使用localCompare 而不是通常的关系运算符——它们在字符串上工作得很好。另请注意,options 在 ES6 中是新的,在旧版浏览器中无法使用。
  • @Bergi,问题有const,所以这是一个ES6问题。
  • @Nina,感谢您展示了许多新手开发人员(包括我自己)经常忽略/不知道的比较选项。我希望有一种方法可以“订阅”您和您的 SO 答案,因为这是我在过去 12 小时内从您那里学到的第二件事。
【解决方案2】:

我猜您想将 Id 与数字进行比较,因此您应该对类似数字的列使用适当的排序函数:

const sortAsc = (propertyName) => (a, b) => a[propertyName] === b[propertyName] ? 0 : +a[propertyName] < +b[propertyName] ? -1 : 1;
const sortDesc = (propertyName) => (a, b) => a[propertyName] === b[propertyName] ? 0 : +a[propertyName] < +b[propertyName] ? 1 : -1;

另一种方法是调整你的表格数据数组,id应该是数字,而不是字符串,在这种情况下你的排序功能也应该工作。

【讨论】:

    【解决方案3】:

    您的比较功能完全没问题。关系运算符在数字和字符串上都是开箱即用的,没有理由使用localeCompare

    它可以正常工作,但是当我对其进行排序时,它并不总是正确排序:它实际上不适用于 ID。

    您的对象数组中的id 属性似乎是字符串,因此它们按字典顺序进行比较。将它们设为实际数字,然后将它们作为数字进行比较。

    它在Naam 上升序工作,但在降序时,它首先给出 2 个以 v 和 k 开头的名称。这是为什么呢?

    在 gif 中真的很难看到,但看起来这两个奇怪的排序值以空格开头 - 总是首先排序。确保您的数据有效。

    【讨论】:

    • 您好,感谢您的回答,但它首先以 v 和 k 开头的原因是因为它们不是小写字母。将其更改为 localeComare 解决了该问题。我不知道我的 id 是否是字符串,我不这么认为,因为我将它们转换为这样的数字:id: &lt;number&gt; null。我现在所做的是,我为数字添加了一种新的排序方法:(propertyName) =&gt; (a, b) =&gt; a[propertyName] - (b[propertyName]); 这可能不是最好的解决方案,但代码看起来不错且可维护且速度很快。
    • 这是一个 TypeScript 声明吗?我不认为这是一个演员表——而且绝对不会发生在你分配实际值的地方(不仅仅是null)。
    • 是的,我认为它是 TypeScript。嗯……所以,不是演员表。好吧,它在 C# 中:P 我对 TypeScript、Angular 和 ES6 有点陌生。
    猜你喜欢
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    • 2011-04-27
    • 2018-03-12
    • 1970-01-01
    • 2023-03-27
    • 2013-12-19
    • 1970-01-01
    相关资源
    最近更新 更多