kartik
kartik

Reputation: 294

Convert array to array of objects with reduce

optimizedRoute = ['Bengaluru', 'Salem', 'Erode', 'Tiruppur', 'Coimbatore']

result = [
  {start: bengaluru, end: salem},
  {start: salem, end: erode},
  {start: erode, end: tiruppur},
  {start: tiruppur, end: coimbatore},
]

I want to convert optimizedRoute to result. I want to do this with ES6 .reduce(). Here is what I've tried:

const r = optimizedRoute.reduce((places, place, i) => {
  const result: any = [];
  places = []
  places.push({
    startPlace: place,
    endPlace: place
  });
  // result.push ({ startplace, endplace, seats: 4 });
  // console.log(result);
  return places;
}, {});
console.log(r)

Upvotes: 24

Views: 9427

Answers (10)

Nitish Narang
Nitish Narang

Reputation: 4184

Solution with ReduceRight, if anyone is looking for.

optimizedRoute.reduceRight((acc, d, i, arr) => 
             i == 0 
                ? acc 
                : [{ start: arr[i -1], end: d }, ...acc]  
            , [])

Upvotes: -1

Bergi
Bergi

Reputation: 664538

reduce doesn't really fit the bill here as you're not trying to reduce the array to a single value.

In a perfect world we would have multi-array map version, usually known as zip, that we could use like

const result = zipWith(optimisedRoute.slice(0, -1),
                       optimisedRoute.slice(1),
                       (start, end) => ({start, end}));

but there is none in JavaScript. The best alternative is to map over a range of indices into the route using Array.from:

const result = Array.from({length: optimisedRoute.length - 1}, (_, index) => {
     const start = optimisedRoute[index];
     const end = optimisedRoute[index + 1];
     return {start, end};
});

Upvotes: 3

Francute
Francute

Reputation: 148

I prefer readability over just short code that solves it

optimizedRoute.reduce((routes, city, index) => {
  const firstCity = index === 0;
  const lastCity = index === optimizedRoute.length - 1;
  if (!firstCity) {
    routes.last().end = city;
  }
  if (!lastCity) {
    routes.push({ start: city });
  }
  return routes;
}, []);

Also, that solution made shorter but killing readability (at least for me), could be:

optimizedRoute.reduce((routes, city) => {
  routes.last().start = city;
  routes.push({ end: city });
  return routes;
}, [{}]).slice(1, -1);

And about last(), it's a function i normally use for readability:

Array.prototype.last = function() { 
  return this[this.length - 1] 
}

Upvotes: 0

Giorgi Moniava
Giorgi Moniava

Reputation: 28654

Since you asked for reduce, here is one way to do it:

let optimizedRoute = ['Bengaluru', 'Salem', 'Erode', 'Tiruppur', 'Coimbatore']
   
let res = optimizedRoute.reduce((accum, item, i)=>{
   if(i == optimizedRoute.length - 1) 
      return accum;
   accum.push({start: item, end: optimizedRoute[i+1]})
   return accum;
}, [])

console.log(res);

Upvotes: 3

Tom Fenech
Tom Fenech

Reputation: 74615

I don't really understand the "with reduce" requirement, since the corresponding code using a loop is immediately readable and requires no explanation:

const optimizedRoute = ['Bengaluru', 'Salem', 'Erode', 'Tiruppur', 'Coimbatore'];
const result = new Array(optimizedRoute.length - 1);

for (let i = 0; i < result.length; ++i) {
  result[i] = {
    start: optimizedRoute[i],
    end: optimizedRoute[i + 1]
  };
}

console.log(result)

It's fun to do clever things sometimes but some of the answers are very complicated compared to this!

Upvotes: 11

kartik
kartik

Reputation: 294

I simplified nina scholz answer, As per nina’s idea, use reduce for getting start and end part of the route and return the end for the next start.

getParts = a => {
  const result = [];
    a.reduce((start, end) => {
      result.push({ start, end });
      return end;
    });
    return result;
};
var optimizedRoute = ['Bengaluru', 'Salem', 'Erode', 'Tiruppur', 'Coimbatore'];
console.log(this.getParts(optimizedRoute));

Upvotes: 2

Nina Scholz
Nina Scholz

Reputation: 386578

You could use reduce for getting start and end part of the route and return the end for the next start.

getParts = a => (                   // take a as array and return an IIFE
    r => (                          // with an initialized result array
        a.reduce((start, end) => (  // reduce array by taking two values
            r.push({ start, end }), // push short hand properties
            end                     // and take the last value as start value for next loop
        )),
        r                           // finally return result
    )
)([]);                              // call IIFE with empty array

const getParts = a => (r => (a.reduce((start, end) => (r.push({ start, end }), end)), r))([]);

var optimizedRoute = ['Bengaluru', 'Salem', 'Erode', 'Tiruppur', 'Coimbatore']

console.log(getParts(optimizedRoute));
.as-console-wrapper { max-height: 100% !important; top: 0; }


@EDIT Grégory NEUT adding explaination

// Two thing to know first :

// When no initial value is provided,
// Array.reduce takes the index 0 as first value and start to loop at index 1

// Doing (x, y, z)
// Will execute the code x, y and z

// Equivalent to :

// x;
// y;
// z;

let ex = 0;

console.log((ex = 2, ex = 5, ex = 3));

// So about the code

const getParts = (a) => {
  // We are creating a new function here so we can have an array where to
  // push data to
  const func = (r) => {
    // Because there is no initial value
    //
    // Start will be the value at index 0 of the array
    // The loop is gonna start at index 1 of the array
    a.reduce((start, end) => {
      console.log(start, end);

      r.push({
        start,
        end,
      });

      return end;
    });

    return r;
  };

  return func([]);
};

// Equivalent
const getPartsEquivalent = (a) => {
  const r = [];

  // Because there is no initial value
  //
  // Start will be the value at index 0 of the array
  // The loop is gonna start at index 1 of the array
  a.reduce((start, end) => {
    console.log(start, end);

    r.push({
      start,
      end,
    });

    return end;
  });

  return r;
};

var optimizedRoute = ['Bengaluru', 'Salem', 'Erode', 'Tiruppur', 'Coimbatore']

console.log(getPartsEquivalent(optimizedRoute));
.as-console-wrapper {
  max-height: 100% !important;
  top: 0;
}

Upvotes: 14

sjahan
sjahan

Reputation: 5950

Here is an example with reduce. I'm not sure this is the most natural way to do this though!

Using reduce feels quite overkill and in that kind of case (but that's just my opinion), where I'd naturally use an index, well, I'd go for a simple for loop.

const optimizedRoute = ['Bengaluru', 'Salem', 'Erode', 'Tiruppur', 'Coimbatore'];
let startCity;
const result = optimizedRoute.reduce((acc, city) => {
  if(startCity) {
    acc.push({start: startCity, end: city});
  }
  startCity = city;
  return acc;
}, []);

console.log(result);

Upvotes: 5

Orelsanpls
Orelsanpls

Reputation: 23515

The following code is using of Spread operator, Ternary operator and Array.reduce.

const optimizedRoute = [
  'Bengaluru',
  'Salem',
  'Erode',
  'Tiruppur',
  'Coimbatore',
];

// Look if we are at dealing with the last value or not
// If we do only return the constructed array
// If we don't, add a new value into the constructed array.

// tmp is the array we are constructing
// x the actual loop item
// xi the index of the item
const lastItemIndex = optimizedRoute.length - 1;

const ret = optimizedRoute.reduce((tmp, x, xi) => xi !== lastItemIndex ? [
  ...tmp,

  {
    start: x,
 
    // We access to the next item using the position of
    // the current item (xi)
    end: optimizedRoute[xi + 1],
  },
] : tmp, []);

console.log(ret);

Upvotes: 2

Mihai Alexandru-Ionut
Mihai Alexandru-Ionut

Reputation: 48367

Another approach is to use map method in combination with slice. For map function, you have to pass a callback function as argument which will be applied for every item from your given array.

optimizedRoute = ['Bengaluru', 'Salem', 'Erode', 'Tiruppur', 'Coimbatore']
var result = optimizedRoute
                .slice(0, -1)
                .map((item, index) => ({start : item, end : optimizedRoute[index + 1]}));
console.log(result);

Upvotes: 12

Related Questions