Reputation: 294
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
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
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
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
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
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
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
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
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
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
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