Get closest greater value in multiple attributes of Array of Objects

I have this array of objects.

var priceArray = [ 
  { "foo": 1, "bar": 2, "price": 3 },
  { "foo": 2, "bar": 123, "price": 124 },
  { "foo": 2, "bar": 2, "price": 5 },
  { "foo": 112, "bar": 2, "price": 75 },
  { "foo": 2, "bar": 3, "price": 5 },
  { "foo": 3, "bar": 2, "price": 3 },
  { "foo": 3, "bar": 4, "price": 7 },
  { "foo": 4, "bar": 3, "price": 4 },
  { "foo": 4, "bar": 4, "price": 6 }
];

I have another array of objects.

var dataArray = [ 
  { foo: 0.25, bar: 1 },
  { foo: 0.5, bar: 1 },
  { foo: 1, bar: 1 },
  { foo: 1, bar: 2 },
  { foo: 2, bar: 1 },
  { foo: 2, bar: 2 },
  { foo: 2, bar: 4 },
  { foo: 3, bar: 2 },
  { foo: 4, bar: 1 },
  { foo: 4, bar: 2 },
  { foo: 4, bar: 4 },
];

I want to add price in dataArray which price row foo and bar values are closest greater in priceArray.

for example - filtered data should like this

var filterDataArray = [ 
  { foo: 0.25, bar: 1, price: 3 },
  { foo: 0.5, bar: 1, price: 3 },
  { foo: 1, bar: 1, price: 3 },
  { foo: 1, bar: 2, price: 3 },
  { foo: 2, bar: 1, price: 5 },
  { foo: 2, bar: 2, price: 5 },
  { foo: 2, bar: 4, price: 7 },
  { foo: 3, bar: 2, price: 3 },
  { foo: 4, bar: 1, price: 4 },
  { foo: 4, bar: 2, price: 4 },
  { foo: 4, bar: 4, price: 6 },
];

If I sort priceArray with foo and bar value with help of these codes and then filter this array with dataArray. So, I didn't get my solution. like -

priceArray = priceArray.sort(function(a, b) {
  return a.foo - b.foo || a.bar - b.bar;
});
  or
priceArray = _.sortBy(( _.sortBy(priceArray, 'bar')), 'foo');
  or
priceArray = _.orderBy(priceArray, ['foo', 'bar'], ['asc', 'asc']);

// create new data array with price
const dataNewArray = [];
dataArray.map(dataObj => {
  const dataNewObj = {};
  for(const priceObject of priceArray) {
    if (dataObj.foo <= priceObject.foo && dataObj.bar <=  priceObject.bar) {
        dataNewObj.foo = dataObj.foo;
        dataNewObj.bar = dataObj.bar;
        dataNewObj.price = priceObject.price;
        break;
    }
  }
  dataNewArray.push(dataNewObj);
});

but it's solution is

dataNewArray = [ 
  { foo: 0.25, bar: 1, price: 3 },
  { foo: 0.5, bar: 1, price: 3 },
  { foo: 1, bar: 1, price: 3 },
  { foo: 1, bar: 2, price: 3 },
  { foo: 2, bar: 1, price: 5 },
  { foo: 2, bar: 2, price: 5 },
  { foo: 2, bar: 4, price: 124 },
  { foo: 3, bar: 2, price: 3 },
  { foo: 4, bar: 1, price: 4 },
  { foo: 4, bar: 2, price: 4 },
  { foo: 4, bar: 4, price: 6 } 
];

So, you can see in this object { foo: 2, bar: 4, price: 124 }, price should be 7, not 124.

How to solve my problem with help of anything js features like Lodash, or any algorithm. I tried many solutions at StackOverflow but maximum solutions for single attribute in object.

1 answer

  • answered 2018-11-08 08:35 Nina Scholz

    You need to sort by the geometric distance of the items and pick the first one which match.

    var priceArray = [{ foo: 1, bar: 2, price: 3 }, { foo: 2, bar: 123, price: 124 }, { foo: 2, bar: 2, price: 5 }, { foo: 112, bar: 2, price: 75 }, { foo: 2, bar: 3, price: 5 }, { foo: 3, bar: 2, price: 3 }, { foo: 3, bar: 4, price: 7 }, { foo: 4, bar: 3, price: 4 }, { foo: 4, bar: 4, price: 6 }],
        dataArray = [{ foo: 0.25, bar: 1 }, { foo: 0.5, bar: 1 }, { foo: 1, bar: 1 }, { foo: 1, bar: 2 }, { foo: 2, bar: 1 }, { foo: 2, bar: 2 }, { foo: 2, bar: 4 }, { foo: 3, bar: 2 }, { foo: 4, bar: 1 }, { foo: 4, bar: 2 }, { foo: 4, bar: 4 }], 
        result;
    
    priceArray.sort((a, b) => 
        (Math.pow(a.foo, 2) + Math.pow(a.bar, 2)) - (Math.pow(b.foo, 2) + Math.pow(b.bar, 2))
    );
    result = dataArray.map(({ foo, bar }) => ({
        foo,
        bar,
        price: priceArray.find(o => o.foo >= foo && o.bar >= bar).price
    }));
    
    console.log(result);     // the result
    console.log(priceArray); // the sorted array
    .as-console-wrapper { max-height: 100% !important; top: 0; }