-2

In my JavaScript, I have an integer that represents an order quantity, and an object of all quantities offered:

    {
        "1": {
            "quantity": 1,
            "price": 10
        },
        "2": {
            "quantity": 2,
            "price": 20
        },
        "6": {
            "quantity": 6,
            "price": 50
        },
        "12": {
            "quantity": 12,
            "price": 80
        }
    }

I need to find the object with a quantity value greater than my order quantity, but smaller than the quantity value of the next object in the sequence.

For example, if my order quantity is 8, I need to isolate:

        "6": {
            "quantity": 6,
            "price": 50
        },

So I can get the correct price. I've tried various LoDash methods, but nothing seems to be quite right. Is there a way that I can achieve this?

Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
Cameron Scott
  • 1,276
  • 2
  • 17
  • 37
  • 2
    You don't have an array there, you have an object. So none of the array methods are going to work. – James Oct 02 '19 at 18:53
  • 1
    *"but smaller than the quantity value of the next array in the sequence"* what do you mean by that? – zfrisch Oct 02 '19 at 18:55
  • If the actual list is small, the simplest method is probably just a naive loop. Iterate through each item and find the best match. If your actual data set is large enough for this to be a performance issue (unlikely), perhaps convert to an array and do a binary search for the best value.. – alttag Oct 02 '19 at 18:57
  • @alttag *"Iterate through each item and find the best match."* <-- I kind of think that's what the OP is asking how to do. – Scott Marcus Oct 02 '19 at 19:00
  • 1
    does the key mirrors the quantity? – Nina Scholz Oct 02 '19 at 19:08

4 Answers4

0

Based on your description, I'm assuming what you're trying to do is find the record corresponding to the lowest quantity higher than the input quantity. The example doesn't actually match that description though. If you're looking for the opposite (next largest, smaller than the input) you could flip the two inequalities.

    some_prices =  {
        "1": {
            "quantity": 1,
            "price": 10
        },
        "2": {
            "quantity": 2,
            "price": 20
        },
        "6": {
            "quantity": 6,
            "price": 50
        },
        "12": {
            "quantity": 12,
            "price": 80
        }
    }

    getNextQuantityPrice = (prices, quantity) => {
        const largerQuantities = Object.values(prices)
            .filter(value => value.quantity > quantity);
        if (largerQuantities.length === 0) return null;
        return largerQuantities
            .reduce((min, next) => next.quantity < min.quantity ? next : min)
    }

    console.log(JSON.stringify(getNextQuantityPrice(some_prices, 2)));
jwde
  • 642
  • 4
  • 13
0

You could take the keys and reverse the array and find the smaller or equal count.

function find(object, quantity) {
    return Object.keys(object).reverse().find(v => v <= quantity);
}

var object = { 1: { quantity: 1, price: 10 }, 2: { quantity: 2, price: 20 }, 6: { quantity: 6, price: 50 }, 12: { quantity: 12, price: 80 } };

console.log(find(object, 8));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Even though this should work by the spec, it depends on the ugly fact that `"12" < 8 //=> false` even though `"12" < "8" //=> true`. Depending on that sort of coercion would worry me. I think it's better to work directly with the numeric values, especially since the requested output includes them. – Scott Sauyet Oct 02 '19 at 19:27
0

If you just need to iterate through keys in a Javascript object, this has been answered many times.

var prices = {
        "1": {
            "quantity": 1,
            "price": 10
        },
        "2": {
            "quantity": 2,
            "price": 20
        },
        "6": {
            "quantity": 6,
            "price": 50
        },
        "12": {
            "quantity": 12,
            "price": 80
        }
    };

for (qty in prices) {
  // Do stuff
  console.log(qty);
}

If you just need to tease out the quantities available (your object keys), use Object.keys(prices), which returns an array you can loop over.

Once the data are in an array, you can do another for loop, or start getting fancy with forEach(), filter(), and the like.

alttag
  • 1,163
  • 2
  • 11
  • 29
0

Like the other answers, I find the best way to deal with the basic question is to reverse the list. But rather than depending upon the original object being ordered the way you like, I think it's best to sort it up front, and then we can just do so in reverse order.

const nextQuantity = (quantities) => {
  const reversed = Object .values (quantities) .sort (({quantity: q1}, {quantity: q2}) => q2 - q1)
  return (requested) => reversed .find (({quantity}) => quantity < requested)
}

const quantities = {1: {quantity: 1, price: 10}, 2: {quantity: 2, price: 20}, 6: {quantity: 6, price: 50}, 12: {quantity: 12, price: 80}}

console .log (
  nextQuantity (quantities) (8)
)

This also gives us a chance to store an intermediate function that doesn't need to reverse the list on every call. nextQuantity(quantities) returns a function you can call repeatedly with each requested quantity.

If you really want the output format from the question (that is, not just {quantity: 6, price: 50} but that result wrapped in a single-property object like {'6': {quantity: 6, price: 50}}) then you could rewrite it as

const nextQuantity = (quantities) => {
  const reversed = Object .values (quantities) .sort (({quantity: q1}, {quantity: q2}) => q2 - q1)
  return (requested) => {
    const q = reversed .find (({quantity}) => quantity < requested)
    return {[q.quantity]: q}
  }
}

But I personally would find that format much harder to work with.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103