The following is not valid ES6 syntax, but perhaps there's a simple way to accomplish the same thing, e.g., using Ramda?
const [...butLast, last] = values
The following is not valid ES6 syntax, but perhaps there's a simple way to accomplish the same thing, e.g., using Ramda?
const [...butLast, last] = values
If you're using ramda you can do this
const values = [1, 2, 3]
const [butLast, Last] = [R.dropLast(1, values), R.last(values)]
R.dropLast(n, arr)
: returns a copy of array arr
with the last n
elements removed
R.last(arr)
: returns the last element in an array
You can reverse the array, use a standard ...rest
operator, and then reverse the rest back:
const initAndLast = (arr) => (([last, ...butLast]) => [butLast.reverse(), last])([...arr].reverse())
const [bl1, l1] = initAndLast([1, 2, 3]);
console.log(`butLast: ${JSON.stringify(bl1)}, last: ${l1}`)
const [bl2, l2] = initAndLast([1]);
console.log(`butLast: ${JSON.stringify(bl2)}, last: ${l2}`)
With ramda, you can use R.init and R.last with R.juxt:
const initAndLast = R.juxt([R.init, R.last]);
const [bl1, l1] = initAndLast([1, 2, 3]);
console.log(`butLast: ${JSON.stringify(bl1)}, last: ${l1}`)
const [bl2, l2] = initAndLast([1]);
console.log(`butLast: ${JSON.stringify(bl2)}, last: ${l2}`)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
You can use Array.prototype.slice()
, Array.prototype.pop()
let values = [1,2,3,4,5];
// copy `values` array using `.slice()`, `.pop()` the copy
// alternatively `values.pop()` to remove last element from `values`
const [butLast, last] = [values, values.slice(0).pop()];
console.log(butLast, last);
You're looking at the problem the wrong way. You don't want the rest operator at the beginning of the destructuring assignment. What you want is to get the elements from the end of the array instead of the beginning. The position of the rest operator is irrelevant to the desired result.
There are two concepts that exist in the object destructuring portion of destructuring assignments that together will allow you to accomplish what you really want using only what the language provides.
These two concepts are:
Assigning values of properties to identifiers whose names differ from that of the property.
const { thing: otherthing } = { thing: 1 };
console.log(otherthing, thing); // 1, undefined
Access properties dynamically:
const prop = 'thing';
const { [prop]: otherthing } = { thing: 1 };
console.log(otherthing, thing); // 1, undefined
These two concepts combined with the fact that arrays are objects, allows you to do the following:
const values = [1,2,3,4,5,6,7,8,9];
const { [values.length - 1]: last, ...rest } = values;
console.log(last, Object.values(rest)); // 9 [1,2,3,4,5,6,7,8]
The downsides being:
You have to know the length of the array, so you have to store the array before destructuring, or include the length property in the destructuring assignment:
const { length, [length - 1]: last, ...rest } = [1,2,3,4,5,6,7,8,9];
console.log(last, Object.values(rest)); // 9 [1,2,3,4,5,6,7,8]
If you want the result of the rest assignment to be a true array you have to use Object.values()
as above to convert the result of the rest assignment back to an array, but you could wrap that in an IIFE to prevent scope interference (this also prevents the scope intereference of the previous downside):
const { last, rest } = (({ length: l, [l-1]: last, ...rest } = [1,2,3,4,5,6,7,8,9]) =>
({ last, rest: Object.values(rest) }))();
console.log(last, rest); // 9 [1,2,3,4,5,6,7,8]