как суммировать дублирующиеся элементы массива - PullRequest
1 голос
/ 29 июня 2019

программа работает нормально, за исключением того, что массив «change» имеет много дубликатов, суммирование дубликатов должно быть простым, за исключением того, что оно дает неправильные суммы! пример: суммирование 3 двадцатых должно дать 60, вместо этого - 80! я заметил, что ошибка происходит только с нечетными дубликатами! Еще одна вещь, которую я не могу понять, это почему массив "change" меняется, когда я суммирую дубликаты? я скопировал массив изменений в другой массив, поэтому, если что-то случится со вторым массивом, это не должно повлиять на массив "изменений"!

программа работает хорошо, пока я не доберусь до той части, где мне нужно суммировать дубликаты (функция sumDuplicates () прекрасно работает сама по себе, но не с моим кодом)

function checkCashRegister(price, cash, cid) {
  var change = [];
  let difference = cash - price;
  let level = 0;
  let currency = [
    ["PENNY", 0.01],
    ["NICKEL", 0.05],
    ["DIME", 0.1],
    ["QUARTER", 0.25],
    ["ONE", 1],
    ["FIVE", 5],
    ["TEN", 10],
    ["TWENTY", 20],
    ["ONE HUNDRED", 100]
  ]
  //sum all money in register
  let totalFunds = cid.reduce((r, [key, value]) => {
    return r + value
  }, 0)

  //function to match the difference to appropriate currency
  function findLevel(dif) {
    for (let i = currency.length - 1; i >= 0; i--) {
      //our change must be the highest availabe currency
      if (dif >= currency[i][1] && cid[i][1] != 0) {
        //console.log(currency[i])
        return i
      }
    }
  }
  //function to subtract
  function subtractor(dif, lvl) {
    if (cid[lvl][1] != 0) {
      dif = dif.toFixed(2)
      dif = dif - currency[lvl][1]
      cid[lvl][1] -= currency[lvl][1]
      change.push(currency[lvl])
      return dif
    }
  }
  //if no change needed
  if (difference == 0) {
    return {
      status: "CLOSED",
      change: []
    }
  }
  //if we dont have enough money to pay back
  if (totalFunds < difference) {
    return {
      status: "INSUFFICIENT_FUNDS",
      change: []
    }
  }
  //if we need to pay change AND we have enough money
  if (difference > 0 && totalFunds >= difference) {
    while (difference >= 0.01) {
      level = findLevel(difference)
      difference = subtractor(difference, level)
      //console.log(difference)
    }
  }

  //to sum duplicate elements in the "change" array, this is the problem!!!
  function sumDuplicates(arr1) {
    let arr = [...arr1]
    let sums = arr.reduce((sums, item) => {
      let found = sums.find(([key]) => key === item[0]);
      //console.log(found)
      if (found)
        found[1] += item[1];
      else
        sums.push(item);
      // console.log(item)
      return sums;
    }, []);
    return sums;
  }
  let sums = sumDuplicates(change)
  console.log(sums);
  return {
    status: "OPEN",
    change: sums
  };
}

checkCashRegister(3.26, 100, [
  ["PENNY", 1.01],
  ["NICKEL", 2.05],
  ["DIME", 3.1],
  ["QUARTER", 4.25],
  ["ONE", 90],
  ["FIVE", 55],
  ["TEN", 20],
  ["TWENTY", 60],
  ["ONE HUNDRED", 100]
]);

Я ожидаю [[twenties,60]] вместо этого я получаю [[twenties,80]]

Ответы [ 2 ]

3 голосов
/ 29 июня 2019

Вы должны быть осторожны, вставляя ссылки в массивы, потому что они не делают копии.Вы делаете это в нескольких местах, и в вашей функции sum вы в конечном итоге модифицируете исходный массив, который изменяет значения в вашей справочной таблице.

if (found)
     found[1] += item[1]; // <-- now modifying your original currency lookup!
else
     sums.push(item);     // <-- your pushing a ref to your original currency lookup!

Быстрое решение - вместо этого нажать копию в вашей функции суммирования:

 sums.push([...item])

A (возможно, лучшая альтернатива) - вставить копию в массив change:

function subtractor(dif, lvl) {
  if (cid[lvl][1] != 0) {
      dif = dif.toFixed(2)
      dif = dif - currency[lvl][1]
      cid[lvl][1] -= currency[lvl][1]
      change.push([...currency[lvl]]) // < push a copy not the original ref
      return dif
   }
 }

function checkCashRegister(price, cash, cid) {
  var change = [];
  let difference = cash - price;
  let level = 0;
  let currency = [
    ["PENNY", 0.01],
    ["NICKEL", 0.05],
    ["DIME", 0.1],
    ["QUARTER", 0.25],
    ["ONE", 1],
    ["FIVE", 5],
    ["TEN", 10],
    ["TWENTY", 20],
    ["ONE HUNDRED", 100]
  ]
  //sum all money in register
  let totalFunds = cid.reduce((r, [key, value]) => {
    return r + value
  }, 0)

  //function to match the difference to appropriate currency
  function findLevel(dif) {
    for (let i = currency.length - 1; i >= 0; i--) {
      //our change must be the highest availabe currency
      if (dif >= currency[i][1] && cid[i][1] != 0) {
        //console.log(currency[i])
        return i
      }
    }
  }
  //function to subtract
  function subtractor(dif, lvl) {
    if (cid[lvl][1] != 0) {
      dif = dif.toFixed(2)
      dif = dif - currency[lvl][1]
      cid[lvl][1] -= currency[lvl][1]
      change.push([...currency[lvl]])  //< -- PUSH A COPY!
      return dif
    }
  }
  //if no change needed
  if (difference == 0) {
    return {
      status: "CLOSED",
      change: []
    }
  }
  //if we dont have enough money to pay back
  if (totalFunds < difference) {
    return {
      status: "INSUFFICIENT_FUNDS",
      change: []
    }
  }
  //if we need to pay change AND we have enough money
  if (difference > 0 && totalFunds >= difference) {
    while (difference >= 0.01) {
      level = findLevel(difference)
      difference = subtractor(difference, level)
      //console.log(difference)
    }
  }

  //to sum duplicate elements in the "change" array, this is the problem!!!
  function sumDuplicates(arr1) {
    let arr = [...arr1]
    let sums = arr.reduce((sums, item) => {
      let found = sums.find(([key]) => key === item[0]);
      //console.log(found)
      if (found)
        found[1] += item[1];
      else
        sums.push(item);  
      // console.log(item)
      return sums;
    }, []);
    return sums;
  }
  let sums = sumDuplicates(change)
  console.log(sums);
  return {
    status: "OPEN",
    change: sums
  };
}

console.log(checkCashRegister(3.26, 100, [
  ["PENNY", 1.01],
  ["NICKEL", 2.05],
  ["DIME", 3.1],
  ["QUARTER", 4.25],
  ["ONE", 90],
  ["FIVE", 55],
  ["TEN", 20],
  ["TWENTY", 60],
  ["ONE HUNDRED", 100]
]));
0 голосов
/ 29 июня 2019

Вот альтернативная, менее подробная версия. Он возвращает объект, указывающий, сколько из каждого счета вам нужно вернуть. - Изменение вычитается из содержимого регистров.

const subtract = (available, current, value) => {
    let cash = available.find ( ([bill]) => bill === current); 
    if (cash [1] < value) throw new Error ('INSUFFICIENT_FUNDS');
    cash [1] -= value;
}
const computeChange = (price, cash, available) => {
	let sorted = currency.sort ((a,b) => a[1] - b[1]);
	let change = {}
    let sum = 0;
    let highest = sorted.pop ();

    do {
      var [bill, value] = highest;
      if ((sum + value) > price) {
         highest = sorted.pop ()
         continue;
      }
      sum += value;
      subtract (available, bill, value);
      change [highest [0]] = -~change [highest [0]]
    } while (highest && sum <= price)

    return change;
} 
let change = computeChange (3.26, 100, register);
console.log (change, register);
<script>
const register = [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]];
let currency = [
    ["PENNY", 0.01],
    ["NICKEL", 0.05],
    ["DIME", 0.1],
    ["QUARTER", 0.25],
    ["ONE", 1],
    ["FIVE", 5],
    ["TEN", 10],
    ["TWENTY", 20],
    ["ONE HUNDRED", 100]
]
</script>
...