Find best Route and Price in an array

Viewed 154

how to tell the customer which route and cheapest price.

For example: how to know which destination is cheaper between Guarulhos to Rio or SaoPaulo to Rio

The form I present in the code I am just adding everything, I would like to display the cheapest of the Keys: Price and Distance

      import React, { Component } from "react";
      import ReactDOM from "react-dom";

      class App extends Component {
        state = {

          routes: [
            { grarulhoserio: 1, Price: 10, Distance: 345, Sigla: 'grarulhos.rio' },
            { grarulhosesantacatarina: 2, Price: 18, Distance: 547, "Sigla": 'grarulhos.santacatarina' },
            { saopauloerio: 3, Price: 10, Distance: 357, Sigla: 'saopaulo.rio' },
            { minasgeraiserio: 4, Price: 75, Distance: 556, Sigla: 'minasgerais.rio' },
            { minasgeraisesantacatarina: 5, Price: 20, Distance: 1180, Sigla: 'minasgerais.santacatarina' },
            { saopauloesantacatarina: 6, Price: 5, Distance: 512, Sigla: 'saopaulo.santacatarina' }
        ]
        };

        onChange = (index, val) => {
          this.setState({
            routes: this.state.routes.map((route, i) =>
              i === index ? { ...route, count: val } : route
            )
          });
        };

        render() {
          return (
            <div>
              <ProductList routes={this.state.routes} onChange={this.onChange} />
              <Total routes={this.state.routes} />
            </div>
          );
        }
      }

      const ProductList = ({ routes, onChange }) => (
        <ul>
          {routes.map((route, i) => (
            <li key={i}>
              {route.Sigla}
              <input
                type="text"
                value={route.Price}
                onChange={e => onChange(i, parseInt(e.target.value) || 0)}
              />
            </li>
          ))}
        </ul>
      );

      const Total = ({ routes }) => (
        <h3>
          Best Values:
          {routes.reduce((sum, i) => (sum += i.Distance * i.Price), 0)}
        </h3>
      );

      ReactDOM.render(<App />, document.querySelector("#root"));
2 Answers

Calculation

You can try something like this (find one route with min Price and one wirh min Distance)

const minRoutesObj = routes.reduce((acc, obj) => {
  if (!acc.minPriceRoute || acc.minPriceRoute.Price > obj.Price) {
    acc.minPriceRoute = obj;
  }

  if (!acc.minDistanceRoute || acc.minDistanceRoute.Distance > obj.Distance) {
    acc.minDistanceRoute = obj;
  }

 return acc;
}, {});

/* {
  minDistanceRoute: { grarulhoserio: 1, Price: 10, Distance: 345, Sigla: 'grarulhos.rio' },
  minPriceRoute: { saopauloesantacatarina: 6, Price: 5, Distance: 512, Sigla: 'saopaulo.santacatarina' }
} */

Then you can use

 const minRoutes = Object.values(minRoutesObj);
/* [{ }, { }] */

In the context of React


const Route = ({ Sigla, Price }) => (
  <li key={Sigla}>
    {Sigla}
    <input
      type="text"
      value={Price}
      onChange={e => onChange(i, parseInt(e.target.value) || 0)}
    />
  </li>
);

const BestRoutes = ({ minDistanceRoute, minPriceRoute }) => (
  <div>
    <p>Min price:</p>
    <Route {...minPriceRoute} />
    <p>Min distance:</p>
    <Route {...minDistanceRoute} />
  </div>
)

class App extends Component {
  state = {
    routes: [
      { grarulhoserio: 1, Price: 10, Distance: 345, Sigla: 'grarulhos.rio' },
      { grarulhosesantacatarina: 2, Price: 18, Distance: 547, "Sigla": 'grarulhos.santacatarina' },
      { saopauloerio: 3, Price: 10, Distance: 357, Sigla: 'saopaulo.rio' },
      { minasgeraiserio: 4, Price: 75, Distance: 556, Sigla: 'minasgerais.rio' },
      { minasgeraisesantacatarina: 5, Price: 20, Distance: 1180, Sigla: 'minasgerais.santacatarina' },
      { saopauloesantacatarina: 6, Price: 5, Distance: 512, Sigla: 'saopaulo.santacatarina' }
    ],
  };

  /* ... */

  calculateMinRoutes() {
    const minRoutesObj = this.state.routes.reduce((acc, obj) => {
      if (!acc.minPriceRoute || acc.minPriceRoute.Price > obj.Price) {
        acc.minPriceRoute = obj;
      }

      if (!acc.minDistanceRoute || acc.minDistanceRoute.Distance > obj.Distance) {
        acc.minDistanceRoute = obj;
      }

     return acc;
    }, {});

    return minRoutesObj || {};
  }

  render() {
    const minRoutesObj = this.calculateMinRoutes();
    return (
      /* ... */
      <BestRoutes {...minRoutesObj} />
    );

  }
}

You can also use LoDash.

cheapest = _.sortBy(routes, ['Distance', 'Price']);

I would add a simple function that you can call during lifecycles or in reponse to onclick

const cheapestRouteBasedOnParams = (arrayOfRoutes, ...sortParams) => {
    return _.sortBy(arrayOfRoutes, [sortParams]
}

The important thing to note with lodash sortBy is that the order of params matter. If you care more about distance put it first.

Good luck. Hope this helps.

Related