4

I know that

var a = [12,23,132,12,3];
var [first, ...rest] = a;

will give first = 12 and rest = [23,132,12,3]

What I would like to do is make rest as the first variable. Something like this

var a = [12,23,132,12,3];
var [...rest, last] = a;

which should give me rest = [12,23,132,12] and last = 3

But this is a wrong syntax and I will get an error that will say

SyntaxError: Rest element must be last element

I know that I can achieve this by reversing the array and then destructuring like this

var a = [12,23,132,12,3];
var [last, secondLast, ...rest] = a.reverse();

which will give me last = 3, secondLast = 12 and rest = [132,23,12] and then I would again have to reverse() the rest.

I can also use indexes and directly access the array elements as well. But that is not desired.

My question is, are there any other ways to achieve what I am trying to do (using rest operators ?) ?

cнŝdk
  • 31,391
  • 7
  • 56
  • 78
Prasanna
  • 4,125
  • 18
  • 41
  • This is not possible due to the design of array destructuring. It takes an iterator as the input, and you don't know beforehand how many items an iterator will yield, so you wouldn't know when to stop pushing to the array and start assigning to the last targets. – Bergi Sep 17 '18 at 10:20
  • Hmm, it's very much possible: `let [last, secondLast, ...rest] = [...a.slice(-2).reverse(), ...a.slice(0, -2)]` – Keyvan Aug 14 '20 at 15:50
  • No reverse needed for the first example: `let [last, ...rest] = [...a.slice(-1), ...a.slice(0, -1)]`, and all without mutation! – Keyvan Aug 14 '20 at 16:03

4 Answers4

6

You can use Destructuring assignment along with Array#pop() method to get the last element, and the rest in your variables:

let [last, ...rest] = [a.pop(), ...a];

You can test the results here and see that pop() is the fastest solution among other ones.

Note:

If we want to keep the original array intact, we just need to add the removed item

a.push(last);
  • The .pop() call will get the last element from the array and affects the original array so there's only the rest of it. That fits exactly your needs.
  • We used a.push(last); to retrieve the initial state of a array, this will avoid cloning the array or having an additional variable to clone the a array.

Demo:

var a = [12, 23, 132, 12, 3];

let [last, ...rest] = [a.pop(), ...a];

a.push(last);

console.log(last);
console.log(rest);
console.log(a);
cнŝdk
  • 31,391
  • 7
  • 56
  • 78
  • Just a minor comment, do `const [last, ...rest] = [ a.pop(), ...a ]`. This would prevent any mutation because of reference – Rajesh Sep 17 '18 at 09:02
  • Why not just `let [last, rest] = [a.pop(), a];`? – Martin Stone Sep 17 '18 at 09:33
  • If you're mutating `a`, why even assign `rest` at all? Just use the modified `a` instead. – Martin Stone Sep 17 '18 at 09:37
  • @MartinStone Yes, in that specific case, you are right, but normally we should clone the array before this to avoid mutating the original array. – cнŝdk Sep 17 '18 at 09:46
  • If the `a` array is mutated we can just call `a.push(last);` after this assignement so we can get back the array to its intial state, this will avoid cloning it and having additional variables. – cнŝdk Sep 17 '18 at 10:06
  • The temporary array is pretty inefficient. You could do just the same without destructuring: `const last = arr.pop(), rest = arr.slice();` – Bergi Sep 17 '18 at 10:21
  • @Bergi Yes absolutely, it is better but it will also affect the original array, but anyway I just used destructing to match the OP requirements as he wanted it. – cнŝdk Sep 17 '18 at 10:24
2

You can use array.slice with negative indexes...

const [others, last] = [a.slice(0,-1), ...a.slice(-1)]
Martin Stone
  • 12,682
  • 2
  • 39
  • 53
1

Per the MDN website on destructuring assignements the rest element on array destructuring is the remaining part of the array so it should always be the last element.

I know you say indexes are not desired but something like a[a.length -1] would solve your problem

ibesora
  • 197
  • 5
  • Yes no indexes. And I know rest should always be the last element, But I was looking for a work around :) – Prasanna Sep 17 '18 at 08:53
1

So far I think mutating the origin array maybe the best way which is better than reversing array several times.

var a = [12, 23, 132, 12, 3];
a.unshift(a.pop())
console.log(a); // [3, 12, 23, 132, 12] 

var [last, ...rest] = a;
console.log(last) // 3
console.log(rest) // [12, 23, 132, 12]
Can Zhang
  • 38
  • 6