重构Javascript函数:数组转换

3

我有一个常量数组,像这样:

const pie_values = [20,10,5,5,10];

挑战在于根据整数输入来转换上述数组。
(5) => [5, 15, 10, 5, 5, 10]
(21) => [20, 1, 9, 5, 5, 10]
(31) => [20, 10, 1, 4, 5, 10]

输入5将从pie_values的第一个索引中取出5。但它仍然剩下15。

输入21可以从索引0中取20,从索引2中取1,剩余9个

我想你能看到这是怎么回事。所以(0)和(50)将返回原始的pie_values。

现在的挑战是创建一个函数,在几行代码上进行循环构建,而不是基于5个if语句。如果pie_values被扩展,该函数仍应正常工作。

我有一个使用if语句的方法,但后者是不可行的。对于这种类型的问题,有什么好的方法?

首先,我定义了一个辅助函数:

//Returns summation of pie value
// totalPieValues(1) = 20
// totalPieValues(2) = 30
// totalPieValues(3) = 35
// totalPieValues(4) = 40
// totalPieValues(5) = 50
function totalPieValues(max) {
  let result = 0;
  for (let i = 0; i < max; i++) {
    result += PIE_VALUES[i];
  }
  return result;
}

然后我开始编写函数getPieArray,利用了这个辅助函数。但是我现在遇到了困难。

function getPieArray(wp) {
  for (let i = 0; i < PIE_VALUES.length; i++) {
    if (wp == 0 || wp == totalPieValues(i)) {
      return PIE_VALUES;
    }
  }

  let result = [];
  for (let i = 1; i <= PIE_VALUES.length; i++) {
    if (wp > totalPieValues(PIE_VALUES.length - i)) {
      result.push(PIE_VALUES[i]);
    } else if () {
      result.push(wp - totalPieValues(3));
    } else {
      result.push(PIE_VALUES[i] - (value - totalPieValues(3)));
    }
  }
  return result;
}

我已经编写并且可用的代码如下:

//Returns array of exact values needed to show in pie chart
export function getPieValues(wp) {
  //1 => [1, 19, 10, 5, 5, 10]
  //24 => [20, 4, 1, 5, 5, 10]
  //31 => [20, 10, 1, 5, 5, 5, 10]
  let result;
  if (wp == 0) {
    result = PIE_VALUES;
  } else if (wp < totalPieValues(1)) {
    result = [wp - totalPieValues(0), PIE_VALUES[0] - wp, PIE_VALUES[1], PIE_VALUES[2], PIE_VALUES[3], PIE_VALUES[4]];

  } else if (wp == totalPieValues(1)) {
    result = PIE_VALUES;
  } else if (wp < totalPieValues(2)) {
    result = [PIE_VALUES[0], wp - totalPieValues(1), PIE_VALUES[1] - (wp - PIE_VALUES[0]), PIE_VALUES[2], PIE_VALUES[3], PIE_VALUES[4]];

  } else if (wp == totalPieValues(2)) {
    result = PIE_VALUES;
  } else if (wp < totalPieValues(3)) {

    result = [PIE_VALUES[0], PIE_VALUES[1], wp - totalPieValues(2), PIE_VALUES[2] - (wp - totalPieValues(2)), PIE_VALUES[3], PIE_VALUES[4]];

  } else if (wp == totalPieValues(3)) {
    result = PIE_VALUES;

  } else if (wp < totalPieValues(4)) {

    result = [PIE_VALUES[0], PIE_VALUES[1], PIE_VALUES[2], wp - totalPieValues(3), PIE_VALUES[3] - (wp - totalPieValues(3)), PIE_VALUES[4]];

  } else if (wp == totalPieValues(4)) {
    result = PIE_VALUES;

  } else if (wp < totalPieValues(5)) {

    result = [PIE_VALUES[0], PIE_VALUES[1], PIE_VALUES[2], PIE_VALUES[3], wp - totalPieValues(4), PIE_VALUES[4] - (wp - totalPieValues(4))];

  } else if (wp == totalPieValues(5)) {
    result = PIE_VALUES;
  }

  return result;
}

你能详细描述一下这个函数应该做什么吗?我没有看到它。 - Ry-
@Ryan说你有一个预定义大小的馅饼。在这种情况下,大小为20、10、5、5和10。现在我想要取总馅饼的1/50,这将使馅饼变成1、19、10、5、5和10。 - Fullhdpixel
8个回答

1

这些答案有些过于复杂了。如果你使用递归函数,只需两行代码就能完成。

const pie_values = [20,10,5,5,10];

// The challenge is to transform the above array based on integer input.
// (5) => [5, 15, 10, 5, 5, 10]
// (21) => [20, 1, 9, 5, 5, 10]
// (31) => [20, 10, 1, 4, 5, 10]

function reshape(num, vals) {
    if (num < vals[0]) return [num, vals[0] - num, ...vals.slice(1)];
    return [vals[0], ...reshape(num - vals[0], vals.slice(1))];
}

console.log(reshape(5, pie_values))
console.log(reshape(21, pie_values))
console.log(reshape(31, pie_values))

关键在于意识到,如果你需要取出的数量小于下一个值,那么你可以从下一个值中取出它,而数组的其余部分将保持不变。
但是,如果你需要取出的数量超过了可用数量,尽可能多地从第一个值中取出,然后从数组的其余部分减去相同的数量。
编辑:请注意,如果您提供的数字大于所有饼图值的总和,这将导致无限递归(导致堆栈溢出)。为了完全安全,您应确保该值小于调用reshape之前的总和。

1

这有点过度杀伐了

你只需要遍历数组并“吃掉”索引值,然后继续即可。

function pieArray(inputArray, value){
   let copyOfValue = value;
   return inputArray.reduce((sum, input, index) => { // <-- index here
     copyOfValue -= input;
     if(copyOfValue > 0){
        sum.push(input);
     }else{
        sum.push(input+copyOfValue);
        sum.push(Math.abs(copyOfValue));
        copyOfValue = Number.MAX_VALUE; //Hacky solution, just change value to max value
     }
     return sum;
   }, []);
}

测试

pieArray([20,10,5,5,10], 5) => [5, 15, 10, 5, 5, 10]

pieArray([20,10,5,5,10], 21) => [20, 1, 9, 5, 5, 10]

pieArray([20,10,5,5,10], 31) => [20, 10, 1, 4, 5, 10]


你检查过输出了吗? - Jaromanda X
它适用于除0和50之外的所有情况。但这不是什么大问题。你有没有办法获取索引? - Fullhdpixel
更新了索引,是的,这只是为了检查输入是否为0,如果是,则执行return [0].concat(inputArray),而另一个则是检查我们是否从未输入值,然后需要删除hacky解决方案。 - Pavlo
实际上,您只需检查输入是否不等于“Number.MAX_VALUE”,这将导致最大值失败,但您真的需要它吗? - Pavlo

1
这是我的方法。我们迭代我们的数组,跟踪当前值 - 并在将每个元素推出到输出数组时从中减去。
有3种情况:
  1. 要么我们当前的计数 >= 输入,所以我们只需推送并继续,
  2. 当前计数为0,所以我们只需推送剩下的所有内容
  3. 当前计数 < 输入,但大于0 - 在这种情况下我们会分裂。
以下是代码:
function transform(input, array) {
    const total = array.reduce((previous, current) => previous + current);
    // It wasn't specified what should happen when the input > total, so we will just throw an error.
    if (input > total) {
        throw new Error('Input cannot be bigger than the sum of elements in the array.');
    }

    let current = input;
    let result = [];

    for (let i = 0; i < array.length; i++) {
        if (current >= array[i]) {
            result.push(array[i]);
            current -= array[i];
        } else if (current === 0) {
            result.push(array[i]);
        } else {
            result.push(current, array[i] - current);
            current = 0;
        }
    }

    return result;
}

0

使用原生JavaScript for循环

看这段代码片段

const pie_values = [20, 10, 5, 5, 10];

var fn = (input) => {
  let array = [];
  for (var i = 0; i < pie_values.length; i++) {
    var n = pie_values[i];
    let calc = n - input;
    if (calc > 0) {
      array.push(n - calc); // Push how many used, i.e n = 20, input = 10.
      array.push(calc); // Push the remaining after subtraction.
      array = array.concat(pie_values.slice(i + 1)); // Add the remaining values from 'pie_values'
      return array;
    } else {
      array.push(n); // Push all this number because was insufficient, i.e n = 20, input = 30
      input = Math.abs(calc); // Remaining for the next iteration.
    }
  }

  return array;
};

console.log(fn(5));
console.log(fn(21));
console.log(fn(31));
console.log(fn(0));
console.log(fn(50));


0

这个很简单而且高效。它不会迭代整个数组,只会迭代到需要的那一点。

const pie_values = [20,10,5,5,10];

function pied(n) {
  var i = 0;
  var total = pie_values[0];

  while (total < n && i < pie_values.length) {
    i++;
    total += pie_values[i];
  }

  if (i < pie_values.length) {
    var diff = total - n;
    if (diff > 0 && n > 0) { 
      return [].concat(
       pie_values.slice(0, i), // the part of the array up to i
        pie_values[i] - diff, // the amount we used of the last element we needed
        diff, // the amount left over
        pie_values.slice(i + 1) // the rest of the array after i
      );
    } else {
      // just return a copy of the original array
      return pie_values.slice();
    }
  } else {
    // n was greater than the total of all elements of the array
    return "went over";
  }
}

console.log(pied(5));


0

const pie_values = [20,10,5,5,10];

function rebaseArr(input){
  var retArr = [];
  var total = 0;
  let isDone = false;
  for(var i in pie_values){
    let currentVal = pie_values[i];
    total += currentVal;
    if(total > input && !isDone){
      let rem = total - input;
      let rem1 = currentVal - rem;
      rem1 !== 0 ? retArr.push(rem1) : 0;
      retArr.push(rem);
      isDone = true;
    } else {
      retArr.push(currentVal);
    }
  }
  return retArr;
}

console.log(rebaseArr(31));
console.log(rebaseArr(1));
console.log(rebaseArr(10));

你能否尝试上述代码。 希望对你有所帮助 :)


0

通常我不建议在JS中使用递归,但是为了好玩,你可以通过解构使用展开和剩余操作符来实现类Haskell模式匹配,并且可能会得到以下结果:

当差值为零时,对于我来说不清楚该怎么做,所以作为一个非常懒惰的人,我选择什么都不做。(最后一个测试将不会返回[20,10,5,0,5,10]

var extend = ([x,...xs],n) => n && x ? x > n ? [n, x-n, ...xs]
                                             : [x, ...extend(xs, n-x)]
                                     : [x,...xs],
    pvs    = [20,10,5,5,10];

console.log(extend(pvs,5));
console.log(extend(pvs,21));
console.log(extend(pvs,31));
console.log(extend(pvs,35));
.as-console-wrapper {
max-height : 100% !important
}


0
你想要这样的东西吗?(与你提供的示例相匹配)
    function getPieValues(integer_input) {
        "use strict";
        let final_arr = pie_values,
            array_sum = pie_values.reduce((pv, cv) =>  pv + cv , 0);

        if(integer_input !== 0 && integer_input !== array_sum) { // For the cases 50 and 0, the array won't be modified
            for(let i = 0; i < pie_values.length; i++) {
                if(pie_values[i] < integer_input) { // if the prompted number is bigger than the current value, we keep up
                    integer_input -= pie_values[i];

                } else { // When it becomes smaller, we add the remainder at the front of the current value, then we modify the next value, and finally we break it so that it doesn't happen next
                    final_arr.splice(i, 0, integer_input);
                    final_arr[i+1] -= integer_input;
                    break;
                }
            }

        }
        return final_arr;
    }

编辑:将其改为函数,并使其能够在0和50上正常工作(抱歉,第一篇帖子;-))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接