微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么使用切换生成器对数组进行排序与​​没有切换生成器的下降结果不同?

如何解决为什么使用切换生成器对数组进行排序与​​没有切换生成器的下降结果不同?

const log = console.log;
let toggle = true;
let students = [
    {name: "Alpha",score: 90,school: "East"},{name: "Georgia",score: 100,{name: "climent",score: 40,school: "Wast"},{name: "Elizabeth",score: 80,{name: "Filipino",score: 95,{name: "Detroit",score: 75,{name: "Beta",]


$("#click").click(()=> { 
  let asc = 1;
  toggle? asc = 1 : asc = -1;
  let sorted = students.sort((a,b)=> { 
        let first = a.name;
        let second = b.name;
        return first > second ? asc * 1 : -1
    })

    for(let i = 0; i < sorted.length; i++) { 
        log(sorted[i])
    }

    toggle = !toggle;
})
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<button id="click">CLICK</button>

在这里,我使用一个变量来更改返回值,以便在负值和正值之间切换。

但是,如果我在这两种情况下都只使用 -1 : -1,为什么我没有得到与切换相同的 desc 结果?它们不是字面上一样吗?第二次单击按钮时,asc 是 -1,所以两者都是 -1 : -1,那么如何产生完美的 desc 排序,但是如果我直接添加 -1 : -1,我会得到不同的结果?

const log = console.log;
let toggle = true;
let students = [
    {name: "Alpha",b)=> { 
        let first = a.name;
        let second = b.name;
        return first > second ? -1 : -1
    })

    for(let i = 0; i < sorted.length; i++) { 
        log(sorted[i])
    }

    toggle = !toggle;
})
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<button id="click">CLICK</button>

第二次点击时,这会产生与第一个不同的结果,我不明白为什么。

我也不明白为什么他们在第二种情况下甚至会改变,尽管这两种情况总是返回 -1,那么为什么结果总是不同?不应该总是一样的吗?我没有得到什么..

解决方法

但是为什么会这样,如果我在这两种情况下只使用 -1 : -1 ,我得到的 desc 结果与切换时的结果不同?它们字面上不一样吗?

不,但原因稍微微妙:数组以不同的顺序开始,并且由于 sort 回调没有遵守其返回内容的约定,{ {1}} 变得容易受到初始条件的影响,产生混乱的结果。请记住,sort 对数组进行就地排序,它不会复制,因此第一次排序(第一次点击)的结果会影响第二次排序的结果(即第二次点击),因为 sort 的顺序不同,并且 students 回调没有正确完成其工作以帮助 sort 将总顺序应用于数组。 sort 回调是否在正常工作并不重要,但既然不是,那就很重要了。

这是您更改的第一个片段,以显示排序前数组的顺序并显示排序期间调用的条目:

sort
const log = console.log;
let toggle = true;
let students = [
    {name: "Alpha",score: 90,school: "East"},{name: "Georgia",score: 100,{name: "Climent",score: 40,school: "Wast"},{name: "Elizabeth",score: 80,{name: "Filipino",score: 95,{name: "Detroit",score: 75,{name: "Beta",]

$("#click").click(()=> { 
    let asc = 1;
    toggle? asc = 1 : asc = -1;
    console.log(`Names before sorting: ${students.map(({name}) => name).join(",")}`);
    let sorted = students.sort((a,b)=> { 
        let first = a.name;
        let second = b.name;
        const result = first > second ? asc * 1 : -1;
        console.log(a.name,b.name,result);
        return result;
    })
    console.log(`Names before sorting: ${students.map(({name}) => name).join(",")}`);

    toggle = !toggle;
})
.as-console-wrapper {
    max-height: 80% !important;
}

这是我们看到的:

第一次点击:

Names before sorting: Alpha,Georgia,Climent,Elizabeth,Filipino,Detroit,Beta
Georgia Alpha 1
Climent Georgia -1
Climent Georgia -1
Climent Alpha 1
Elizabeth Climent 1
Elizabeth Georgia -1
Filipino Elizabeth 1
Filipino Georgia -1
Detroit Elizabeth -1
Detroit Climent 1
Beta Elizabeth -1
Beta Climent -1
Beta Alpha 1
Names before sorting: Alpha,Beta,Georgia

第二次点击:

Names before sorting: Alpha,Georgia
Beta Alpha -1
Climent Beta -1
Detroit Climent -1
Elizabeth Detroit -1
Filipino Elizabeth -1
Georgia Filipino -1
Names before sorting: Georgia,Alpha

因此进入第二个排序,条目的顺序是 Alpha、Beta、Climent、底特律、伊丽莎白、菲律宾、乔治亚。

这是具有相同更改的第二个片段:

<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<button id="click">CLICK</button>
const log = console.log;
let toggle = true;
let students = [
    {name: "Alpha",]


$("#click").click(()=> { 
    let asc = 1;
    toggle? asc = 1 : asc = -1;
    console.log(`Names before sorting: ${students.map(({name}) => name).join(",b)=> { 
        let first = a.name;
        let second = b.name;
        const result = first > second ? -1 : -1;
        console.log(a.name,result);
        return result;
    })
    console.log(`Names after sorting: ${students.map(({name}) => name).join(",")}`);

    toggle = !toggle;
})
.as-console-wrapper {
    max-height: 80% !important;
}

第一次点击产生:

Names before sorting: Alpha,Beta
Georgia Alpha -1
Climent Georgia -1
Elizabeth Climent -1
Filipino Elizabeth -1
Detroit Filipino -1
Beta Detroit -1
Names after sorting: Beta,Alpha

注意末尾的随机名称顺序:Beta、Detroit、Filipino、Elizabeth、Climent、Georgia、Alpha

第二次点击:

Names before sorting: Beta,Alpha
Detroit Beta -1
Filipino Detroit -1
Elizabeth Filipino -1
Climent Elizabeth -1
Georgia Climent -1
Alpha Georgia -1
Names after sorting: Alpha,Beta

由于起点不同,<script src="https://code.jquery.com/jquery-3.6.0.js"></script> <button id="click">CLICK</button>回调违反了约定,sort产生了混乱的结果。由于初始条件不同,结果也不同。


在您提出的评论中:

我不明白 3 件事:

  1. 违约是什么意思?你指的是什么合同?您是说 sort() 的默认行为吗?

此处的“契约”是 sort 的回调预期根据 the specification of sort 执行的操作:

如果 comparefn 不是未定义的,它应该是一个接受两个参数 xy 的函数,如果 返回一个负数>x y,如果 x > y 则为正数,否则为零。

sort 依靠回调来完成它的工作。如果(例如)您为 sort-1 返回 "x"(“x 在 y 之前”),"y"-1,否则它无法正常工作和 "y"(“y 在 z 之前”), "z" 用于 -1"z" - 这是废话,z 不能在之前x 如果 x 在 y 之前并且 y 在 z 之前。 "x" 如果排序回调没有完成它的 工作,就无法完成它的工作。

  1. 为什么元素的顺序很重要?我认为所有元素在所有组合中都相互配对,那么为什么初始顺序会有所不同?

不,那将是一种非常低效的排序算法。在有效的排序算法中,只比较确定顺序所需的最少元素组合数。 (这是一个过于简单化的问题;排序是一个难题,并且有许多不同的解决方案具有不同的内存要求等。)如果一个算法比较了 sort"x" 并了解到“x 比 y 更早”,它比较了 "y""y" 并了解到“y 在 z 之前”,它不必比较 "z""x" 因为它已经知道“x在 z 之前”(因为“x 在 y 之前”和“y 在 z 之前”)。 (无论如何它最终可能不得不这样做;同样,排序是一个难题,有很多不同的解决方案。)

但即使它做了所有可能的组合,它也无法调和“x在y之前”和“y在z之前”和“z在y之前”的矛盾信息。

  1. 为什么第一个片段的第二次点击与第一次点击相比,比较的数组元素组合更少?

因为该算法根据 "z" 回调中的信息完成了它需要做的所有工作,只需进行该数量的比较。该算法不必进行更多比较,因为它告诉它的信息就是所有必要的比较。当然,该信息是错误的,因此结果也是错误的,但算法必须假设它被告知的是事实。

我建议您阅读一些更基本的 sorting algorithms,甚至可能使用您的姓名样本集来研究它们,看看如果“这是在此之前吗?”这个问题的答案会发生什么?即使没有意义,也总是“是”。


所有这些都是再见的。当 sort 回调不遵守其约定时获得的结果并不重要,并且可能因 JavaScript 引擎而异(甚至版本与版本),因为规范不需要特定的排序算法(只是特定的结果)。这些算法期望回调完成它的工作,并告诉算法给它的两个元素的相对排名是什么。向这些算法提供不正确的信息会给您带来混乱的结果。

忽略第二个片段,第一个片段中的sort回调存在三个问题;尽管它似乎可以处理您提供的数据,但它不能可靠地处理所有输入。问题是:

  1. 它永远不会返回 sort,但是当元素相等时它应该会这样做。在您的示例中这不是问题的唯一原因是没有一个名称是相同的,但当然对于真实数据,这很重要。

  2. 您仅在返回“较大”指示符时使用 0,而不在返回“较小”指示符时使用,因为 asc 部分缺少 asc :。因此,当 return first > second ? asc * 1 : -1asc 时,您的回调(如您所见)将始终返回 -1。这会产生混乱的结果。

  3. 您在字符串上使用关系运算符,除了仅用英文字母 -1 写的东西外,通常不会产生正确的结果,因为它们比较字符代码,而不是适当的相关词典字符串的位置。使用 localeCompare 以更合适的方式比较字符串,以便(例如)a-z 不在 z 之前。

é 回调应该是:

sort

更新的片段:

return a.name.localeCompare(b.name) * asc;
const log = console.log;
let toggle = true;
let students = [
    {name: "Alpha",]


$("#click").click(()=> { 
  // No reason to have to separate assignments
  let asc = toggle ? 1 : -1;
  let sorted = students.sort((a,b)=> { 
        return a.name.localeCompare(b.name) * asc;
    })

    log("Result:");
    for(let i = 0; i < sorted.length; i++) { 
        log(sorted[i])
    }

    toggle = !toggle;
})

<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<button id="click">CLICK</button>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?