#StackBounty: #javascript #mathematics Find the best matching combination of numbers

Bounty: 100

I need to manipulate chunks quantity until total will be as close as possible to the requirements. Decimals are ok in the quantity.

Again: I can change only quantity property.

So if the requirements are {a:500; b:1200; c:1500}, then the quantity field in the chunks array should be changed so that when I run this:

// sum all chunks
Object.keys(chunks).forEach(chunk=> {
  Object.keys(total).forEach(id=> {
    total[id] += chunks[chunk].payload[id] * chunks[chunk].quantity
  });

It returns an object as close as possible to {a:500; b:1200; c:1500}.

How do I do that efficiently?

const chunks = { // <- the chunks
  chunk1: {
    quantity: 0, // <- the quantity
    payload: { a: 19, b: 17, c: 10 } 
  },
  chunk2: {
    quantity: 0, // <- the quantity
    payload: { a: 17, b: 11, c: 15 } 
  },
  chunk3: {
    quantity: 0, // <- the quantity
    payload: { a: 7, b: 19, c: 0 } 
  },
  chunk4: {
    quantity: 0, // <- the quantity
    payload: { a: 14, b: 4, c: 19 } 
  },
  chunk5: {
    quantity: 0, // <- the quantity
    payload: { a: 3, b: 15, c: 6 } 
  },
  chunk6: {
    quantity: 0, // <- the quantity
    payload: { a: 10, b: 16, c: 3 } 
  },
  chunk7: {
    quantity: 0, // <- the quantity
    payload: { a: 2, b: 3, c: 2 } 
  },
  chunk8: {
    quantity: 0, // <- the quantity
    payload: { a: 14, b: 16, c: 11 } 
  },
  chunk9: {
    quantity: 0, // <- the quantity
    payload: { a: 7, b: 2, c: 2 } 
  },
  chunk10: {
    quantity: 0, // <- the quantity
    payload: { a: 1, b: 7, c: 17 }
  }
}

const requirements = { // <- the requirements
  a: 500,
  b: 1200,
  c: 1500
}

const total = {
  a: 0,
  b: 0,
  c: 0
}

// sum all chunks
Object.keys(chunks).forEach(chunkId => {
  Object.keys(total).forEach(propId => {
    total[propId] += chunks[chunkId].payload[propId] * chunks[chunkId].quantity
  })
})

console.log(total) // <- i need this to be as close as possible to the `requirements`.

// MY SOLUTION:
const percentages = JSON.parse(JSON.stringify(chunks))
Object.keys(percentages).forEach(chunkId => {
  let total = 0
  Object.keys(percentages[chunkId].payload).forEach(propId => {
    const perc =
      percentages[chunkId].payload[propId] / (requirements[propId] / 100)
    percentages[chunkId].payload[propId] = perc
    total += perc
  })
  Object.keys(percentages[chunkId].payload).forEach(propId => {
    percentages[chunkId].payload[propId] =
      percentages[chunkId].payload[propId] / (total / 100)
  })
})

const myTotal = {
  a: 0,
  b: 0,
  c: 0
}

Array.from(Array(10)).forEach(() => {
  Object.keys(percentages).forEach(chunkId => {
    let highestPropId
    let highestPropPercentage = 0
    Object.keys(percentages[chunkId].payload).forEach(propId => {
      const perc = percentages[chunkId].payload[propId]
      if (perc > highestPropPercentage) {
        highestPropPercentage = perc
        highestPropId = propId
      }
    })
    const remainingNum = requirements[highestPropId] - myTotal[highestPropId]
    const koe = 0.5
    const multiplier =
      (remainingNum / chunks[chunkId].payload[highestPropId]) * koe
    Object.keys(myTotal).forEach(propId => {
      myTotal[propId] += chunks[chunkId].payload[propId] * multiplier
    })
    chunks[chunkId].quantity += multiplier
  })
})

console.log('myTotal', myTotal)
/*
in the console log output you'll see this:
{
  "a": 499.98450790851257,
  "b": 1202.1742982865637,
  "c": 1499.5877967505367
}
compare it with the `requirements` object above:
const requirements = { // <- the requirements
  a: 500,
  b: 1200,
  c: 1500
}
as you see, it's almost the same. I need more efficient solution
*/

It’s not accurate and quite inefficient. Any better options?

Notes, answering the first comment:

  • Second snippet contains first snippet and my solution.
  • The quantity is a property in chunks object. Find it in the very beginning of the first snippet
  • "As close as possible" means as close to requirements as mathematically possible.
  • Input is in the first code snippet. To get output, pls run the first snippet.


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.