如何解决为什么使用切换生成器对数组进行排序与没有切换生成器的下降结果不同?
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 件事:
- 违约是什么意思?你指的是什么合同?您是说 sort() 的默认行为吗?
此处的“契约”是 sort
的回调预期根据 the specification of sort
执行的操作:
如果 comparefn 不是未定义的,它应该是一个接受两个参数 x 和 y 的函数,如果 返回一个负数>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"
如果排序回调没有完成它的 工作,就无法完成它的工作。
- 为什么元素的顺序很重要?我认为所有元素在所有组合中都相互配对,那么为什么初始顺序会有所不同?
不,那将是一种非常低效的排序算法。在有效的排序算法中,只比较确定顺序所需的最少元素组合数。 (这是一个过于简单化的问题;排序是一个难题,并且有许多不同的解决方案具有不同的内存要求等。)如果一个算法比较了 sort
和 "x"
并了解到“x 比 y 更早”,它比较了 "y"
和 "y"
并了解到“y 在 z 之前”,它不必比较 "z"
和 "x"
因为它已经知道“x在 z 之前”(因为“x 在 y 之前”和“y 在 z 之前”)。 (无论如何它最终可能不得不这样做;同样,排序是一个难题,有很多不同的解决方案。)
但即使它做了所有可能的组合,它也无法调和“x在y之前”和“y在z之前”和“z在y之前”的矛盾信息。
- 为什么第一个片段的第二次点击与第一次点击相比,比较的数组元素组合更少?
因为该算法根据 "z"
回调中的信息完成了它需要做的所有工作,只需进行该数量的比较。该算法不必进行更多比较,因为它告诉它的信息就是所有必要的比较。当然,该信息是错误的,因此结果也是错误的,但算法必须假设它被告知的是事实。
我建议您阅读一些更基本的 sorting algorithms,甚至可能使用您的姓名样本集来研究它们,看看如果“这是在此之前吗?”这个问题的答案会发生什么?即使没有意义,也总是“是”。
所有这些都是再见的。当 sort
回调不遵守其约定时获得的结果并不重要,并且可能因 JavaScript 引擎而异(甚至版本与版本),因为规范不需要特定的排序算法(只是特定的结果)。这些算法期望回调完成它的工作,并告诉算法给它的两个元素的相对排名是什么。向这些算法提供不正确的信息会给您带来混乱的结果。
忽略第二个片段,第一个片段中的sort
回调存在三个问题;尽管它似乎可以处理您提供的数据,但它不能可靠地处理所有输入。问题是:
-
它永远不会返回
sort
,但是当元素相等时它应该会这样做。在您的示例中这不是问题的唯一原因是没有一个名称是相同的,但当然对于真实数据,这很重要。 -
您仅在返回“较大”指示符时使用
0
,而不在返回“较小”指示符时使用,因为asc
部分缺少asc
:
。因此,当return first > second ? asc * 1 : -1
为asc
时,您的回调(如您所见)将始终返回-1
。这会产生混乱的结果。 -
您在字符串上使用关系运算符,除了仅用英文字母
-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 举报,一经查实,本站将立刻删除。