简体   繁体   English

基于出现次数的数组排序

[英]Array sorting based on number of occurrences

Can someone explain what is happening in this code?有人可以解释这段代码中发生了什么吗?

Question问题

Sort array in descending order based on the number of occurrences of an element根据元素出现的次数降序排列数组

sample input:示例输入:

let chocoArr= ["red", "blue", "green", "red"];

sample output:样本 output:

["red", "red", "blue", "green"]

Code代码

 let chocoArr = ["red", "blue", "green", "red"]; const sortChocolateBasedOnCount = (chocolates) => { let cho = chocolates.reduce(function(temp1, temp2) { if (temp2 in temp1) { temp1[temp2]++; } else { temp1[temp2] = 1; } return temp1; }, {}); let Array = chocolates.sort((temp1, temp2) => { if (cho[temp2] > cho[temp1]) { return 1; } if (cho[temp2] < cho[temp1]) { return -1; } if (temp1 > temp2) { return 1; } if (temp1 < temp2) { return -1; } }); chocolates = Array; } console.log(sortChocolateBasedOnCount(chocoArr));

There are some issues with this code.此代码存在一些问题。

  • First thing is the function sortChocolateBasedOnCount doesnot return a value, That I have fixed in below code首先是 function sortChocolateBasedOnCount不返回值,我已在下面的代码中修复
  • Inside the sortChocolateBasedOnCount function a variable is named as Array , that is not allowed.sortChocolateBasedOnCount function 中,一个变量被命名为Array ,这是不允许的。 Array is a reserved keyword which cannot be used as variable name. Array是保留关键字,不能用作变量名。

Initially your function sortChocolateBasedOnCount recieves an array as the argument.最初,您的 function sortChocolateBasedOnCount一个数组作为参数。 This array is same as chocoArr .该数组与chocoArr相同。 This array is reduced into an Object usung Array.reduce .该数组被缩减为 Object usung Array.reduce

The reduce function loops through the values in the input color array. reduce function 循环遍历输入颜色数组中的值。 These value are saved as the keys of accumularor and the values will be the count of same.这些值被保存为 accumularor 的键,值将是相同的计数。 The loop will be executed 4 times, since the input array has 4 items.循环将执行 4 次,因为输入数组有 4 个项目。 Please find the below list for the values of Initial value of the accumulator and the current value, when the loop starts execution, also the Final Value of Accumulator stored when the loop execution is over.请在下面的列表中找到累加器的初始值和当前值,当循环开始执行时,以及当循环执行结束时存储的累加器的最终值。

If the key is found for first time, the value will be saved as 1 and the value will be incremented for further occurances如果第一次找到该键,则该值将保存为 1,并且该值将在以后出现时递增

  • Itration 1: Accumulator Initial: {} , CurrentValue: red , Accumulator Final { red: 1 }迭代 1:累加器初始值: {} ,当前值: red ,累加器最终值{ red: 1 }
  • Itration 2: Accumulator Initial: { red: 1 } , CurrentValue: blue , Accumulator Final { red: 1, blue: 1 } Itration 2:累加器初始: { red: 1 } ,当前值: blue ,累加器最终{ red: 1, blue: 1 }
  • Itration 3: Accumulator Initial: { red: 1, blue: 1 } , CurrentValue: green , Accumulator Final { red: 1, blue: 1, green: 1 } Itration 3:累加器初始: { red: 1, blue: 1 } ,当前值: green ,累加器最终{ red: 1, blue: 1, green: 1 }
  • Itration 4: Accumulator Initial: { red: 1, blue: 1, green: 1 } , CurrentValue: red , Accumulator Final { red: 2, blue: 1, green: 1 } Itration 4:累加器初始值: { red: 1, blue: 1, green: 1 } ,CurrentValue: red ,累加器最终值{ red: 2, blue: 1, green: 1 }

The output of the reduce function will be the name of color as key and the count of each color in the array as value. reduce function 的 output 将颜色名称作为键,数组中每种颜色的计数作为值。

{ red: 2, blue: 1, green: 1 }

Find the first log in the fiddle for the above.在上面的小提琴中找到第一个日志。

Your input array which is the color list array is next sorted based on the count in the above object based on below logic您的输入数组是颜色列表数组,接下来根据以下逻辑根据上述 object 中的计数进行排序

  • Inital sorting is done based on value for each key returned from reduce function. That is handled by first two if初始排序是根据从 reduce function 返回的每个键的值完成的。这由前两个 if 处理
  • If both have same count then alphabetical sorting is done with last two if.如果两者具有相同的计数,则对最后两个 if 进行字母排序。
  • If none of the conditions are met the sort function should return 0如果不满足任何条件,排序 function 应返回0

Updated Code更新代码

 let chocoArr = ["red", "blue", "green", "red"]; const sortChocolateBasedOnCount = (chocolates) => { let cho = chocolates.reduce(function (temp1, temp2) { // temp1 holds the accumulator // temp2 holds the current value of array loop if (temp2 in temp1) { temp1[temp2]++; } else { temp1[temp2] = 1; } return temp1; }, {}); console.log(cho); let sortedAray = chocolates.sort((temp1, temp2) => { if (cho[temp2] > cho[temp1]) { return 1; } if (cho[temp2] < cho[temp1]) { return -1; } if (temp1 > temp2) { return 1; } if (temp1 < temp2) { return -1; } return 0; }); return sortedAray; } console.log(sortChocolateBasedOnCount(chocoArr));

A clear version of code updating some variable namings will look like below.更新一些变量命名的清晰代码版本如下所示。

 let chocoArr = ["red", "blue", "green", "red"]; const sortChocolateBasedOnCount = (chocolates) => { let reducedChocolate = chocolates.reduce(function (acc, curr) { if (curr in acc) { acc[curr]++; } else { acc[curr] = 1; } return acc; }, {}); console.log(reducedChocolate); let sortedAray = chocolates.sort((a, b) => { if (reducedChocolate[b] > reducedChocolate[a]) { return 1; } if (reducedChocolate[b] < reducedChocolate[a]) { return -1; } if (a > b) { return 1; } if (a < b) { return -1; } return 0; }); return sortedAray; } console.log(sortChocolateBasedOnCount(chocoArr));

The issues with the code:代码的问题:

  1. let Array = while not wrong, if you wanted to do new Array or some other Array method (not instance, but Array.from etc) later in that function, it would not work, since you've clobbered Array with the result of the sort let Array =虽然没有错,但如果您想稍后在 function 中执行new Array或其他一些Array方法(不是实例,而是 Array.from 等),它不会工作,因为您已经用种类
  2. chocolates = Array; is pointless, has no effect on anything at all毫无意义,对任何事情都没有影响
  3. the function doesn't return any value similar operation on a list of fruits for instance function 不返回任何值,例如对水果列表进行类似操作
  4. the sort never returns 0 (when both elements are equal) instead it returns undefined - works, but poor practice排序从不返回 0(当两个元素相等时),而是返回undefined - 有效,但实践不佳
  5. the choice of argument names, especially for the reduce, is poor, to say the least至少可以说,参数名称的选择,尤其是对于 reduce,是很差的

So, fixing these first 3 issues, and the other 2 "style problems"因此,解决前 3 个问题,以及其他 2 个“样式问题”

 let chocoArr = ["red", "blue", "green", "red"]; const sortChocolateBasedOnCount = (chocolates) => { let counts = chocolates.reduce(function(accumulator, choco) { if (choco in accumulator) { accumulator[choco]++; } else { accumulator[choco] = 1; } return accumulator; }, {}); let result = chocolates.sort((a, b) => { if (counts[b] > counts[a]) { return 1; } if (counts[b] < counts[a]) { return -1; } if (a > b) { return 1; } if (b < a) { return -1; } return 0; }); // important note - the incoming array WILL be sorted too //chocolates = result; //doesn't achieve anything return result; } console.log(sortChocolateBasedOnCount(chocoArr)); console.log(chocoArr);


But, you can do better, because, the function name is a little to restrictive, what if you wanted to do a similar sort on fruits, create an identical function called sortFruitsBasedOnCount ?但是,你可以做得更好,因为 function 这个名字有点限制,如果你想对水果做类似的排序,创建一个相同的 function 叫做sortFruitsBasedOnCount怎么办? that'd be redundant那会是多余的

Also, if you don't want to mutate the original array, you can do something about that too另外,如果你不想改变原始数组,你也可以做一些事情

The mix of function (temp1, temp2) in the reduce and (temp1, temp2) => in sort... why? function (temp1, temp2)在 reduce 和(temp1, temp2) => in sort 中的混合...为什么? use one style if you can (and you can)如果可以(并且可以),请使用一种样式

So, let's make some more changes所以,让我们再做一些改变

 let chocoArr = ["red", "blue", "green", "red"]; const sortOnWordCount = (words) => { const counts = words.reduce((acc, word) => { acc[word] = (acc[word] || 0) + 1; return acc; }, {}); return [...words].sort((a, b) => { const diff = counts[b] - counts[a]; if (diff) { return diff; } return a.localeCompare(b); }); } console.log(sortOnWordCount(chocoArr).join()); console.log(chocoArr.join()); // note this is unchanged // same function, different array let fruitArr = ["banana", "apple", "banana", "orange"]; console.log(sortOnWordCount(fruitArr).join());

imagine if that last line was想象如果最后一行是

 sortChocolateBasedOnCount(fruitArr);

It would look odd看起来很奇怪

acc[word] = (acc[word] || 0) + 1; - perfectly valid alternative to the if/else in the original code - 原始代码中if/else的完全有效替代

replace [...words].sort with just words.sort and the incoming array will be mutated as it is in the first code[...words].sort替换为words.sort并且传入的数组将像在第一个代码中一样发生变化

in sort, you can return a negative, positive or zero... not just -1 1 and 0在排序中,您可以返回负数、正数或零……而不仅仅是 -1 1 和 0

so, const diff = counts[b] - counts[a];所以, const diff = counts[b] - counts[a]; calculates the difference (so we only need to do the counts[a] stuff once, not twice计算差异(所以我们只需要做一次counts[a]事情,而不是两次

If that's not zero, just return it如果那不是零,就返回它

Otherwise, use the string localeCompare method which returns -1, 0 or 1 depending on the lexical order of the two strings... one line instead of effectively 5否则,使用字符串 localeCompare 方法,该方法根据两个字符串的词法顺序返回 -1、0 或 1 ...一行而不是有效的 5


If small code size wins points - but still with meaningful funciton names如果小代码量赢得积分 - 但仍然具有有意义的函数名称

 let chocoArr = ["red", "blue", "green", "red"]; const sortOnWordCount = (words) => { const counts = words.reduce((acc, word) => (acc[word] = (acc[word] || 0) + 1, acc), {}); return [...words].sort((a, b) => (counts[b] - counts[a]) || a.localeCompare(b)); }; console.log(sortOnWordCount(chocoArr));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM