【问题标题】:Array sorting based on number of occurrences基于出现次数的数组排序
【发布时间】:2021-08-17 07:34:46
【问题描述】:

谁能解释这段代码中发生了什么?

问题

根据元素出现的次数对数组进行降序排序

样本输入:

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

样本输出:

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

代码

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));

【问题讨论】:

  • 您还要求我们澄清什么?
  • 是的,你没有从你的函数中返回任何东西,你正在覆盖 Array 类! - 你也在对颜色名称进行排序,在你之前的问题中,你说你不想这样做
  • 我的老师给了我这个代码作为这个问题的答案。但我不明白这段代码中发生了什么来对数组进行排序
  • 这不是最好的代码...令人失望的老师。除了已经提到的问题,排序回调从不返回 0。
  • 您的问题应该更加具体。这段代码真正解决了两个问题:计数出现次数,然后排序。您应该具体说明您不了解的内容。您是否在使用调试器单步执行代码时检查了变量?请注意,代码有几个问题,因此如果不列出代码编写者显然使用/拥有的所有不良做法和误解,它并不真正适合解释算法。简而言之:这个问题太宽泛了。展示我们的工作,并做到具体。

标签: javascript arrays sorting


【解决方案1】:

此代码存在一些问题。

  • 首先是函数sortChocolateBasedOnCount 没有返回值,我已在下面的代码中修复
  • sortChocolateBasedOnCount 函数中,一个变量被命名为Array,这是不允许的。 Array 是保留关键字,不能用作变量名。

最初,您的函数sortChocolateBasedOnCount 接收一个数组作为参数。该数组与chocoArr 相同。使用Array.reduce,这个数组被简化为一个对象。

reduce 函数循环遍历输入颜色数组中的值。这些值被保存为 accumularor 的键,并且这些值将是相同的计数。循环将执行 4 次,因为输入数组有 4 个项目。累加器的初始值和当前值的值,循环开始执行时,以及循环执行结束时存储的累加器的最终值,请参见下表。

如果第一次找到该键,值将被保存为 1,并且值将增加以供进一步出现

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

reduce 函数的输出将以颜色名称为键,数组中每种颜色的计数为值。

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

在上面的小提琴中找到第一个日志。

您的输入数组(即颜色列表数组)接下来将根据上述对象中的计数基于以下逻辑进行排序

  • 初始排序是根据reduce 函数返回的每个键的值完成的。由前两个 if 处理
  • 如果两者的计数相同,则使用最后两个 if 进行字母排序。
  • 如果不满足任何条件,排序函数应返回0

更新代码

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));

更新一些变量命名的清晰代码版本如下所示。

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));

【讨论】:

  • 如果您要修复代码,请修复参数名称的选择!!! temp1,temp2 在减少?仍然排序永远不会返回零,只是 1-1undefined - 这几乎没有改善代码
  • @Bravo 同意,我已经在答案中更新了这一点。
【解决方案2】:

代码的问题:

  1. let Array = 虽然没有错,但如果您想稍后在该函数中执行 new Array 或其他一些 Array 方法(不是实例,而是 Array.from 等),它不会起作用,因为您已经用排序结果
  2. chocolates = Array; 毫无意义,对任何事情都没有影响
  3. 函数不返回任何值 例如对水果列表的类似操作
  4. 排序从不返回 0(当两个元素相等时)而是返回 undefined - 有效,但实践不佳
  5. 参数名称的选择,尤其是对于 reduce,至少可以说是很差的

所以,解决前 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);

但是,你可以做得更好,因为函数名称有点限制,如果你想对水果做类似的排序,创建一个名为 sortFruitsBasedOnCount 的相同函数怎么办?那是多余的

另外,如果你不想改变原始数组,你也可以做一些事情

reduce 中的function (temp1, temp2) 和排序中的(temp1, temp2) =&gt; 的混合......为什么?如果可以(并且可以)使用一种风格

所以,让我们再做一些改变

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());

想象一下,如果最后一行是

 sortChocolateBasedOnCount(fruitArr);

看起来很奇怪

acc[word] = (acc[word] || 0) + 1; - 原始代码中if/else 的完美替代方案

[...words].sort 替换为words.sort,传入的数组将像第一个代码中一样发生变异

在排序中,您可以返回负数、正数或零……而不仅仅是 -1 1 和 0

所以,const diff = counts[b] - counts[a]; 计算差异(所以我们只需要执行一次 counts[a] 的东西,而不是两次

如果不为零,则返回它

否则,使用字符串 localeCompare 方法,该方法根据两个字符串的词法顺序返回 -1、0 或 1 ... 一行而不是有效的 5


如果小代码量赢得积分 - 但仍然具有有意义的功能名称

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));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-16
    • 2014-10-25
    • 1970-01-01
    • 1970-01-01
    • 2015-10-09
    相关资源
    最近更新 更多