17

Say I have a function:

function linesReverser(lines) {
  var localLines = lines.slice(); 
  localLines[1].reverse(); 
  return _.flatten(localLines);
}

And using it like so:

var input = [["Hello"],["Hello", "World"]["Attention", "Please"]];
var output1 = linesReverser(input); //["Hello", "World", "Hello", "Attention", "Please"]
var output2 = linesReverser(input); //["Hello", "Hello", "World", "Attention", "Please"]

Notice how the object reference is being shared. I am new to JS, but I thought copying the values would alleviate this issue (line.slice()), but it doesn't seem to work. Is this because of the nested arrays?

How can I non-destructively/immutably perform a reverse?

4 Answers 4

27

You can duplicate the array using ES6's spread operator, then destructively reverse the duplicate:

const arr1 = [1,2,3];
const arr2 = [...arr1].reverse();
// arr1 => [1,2,3]
// arr2 => [3,2,1]
Sign up to request clarification or add additional context in comments.

1 Comment

This deserves far more upvotes. Cleanest solution, given the insanity that reverse() is destructive.
6

You're making a shallow copy of the lines array. To copy the nested arrays, you need to slice each one.

var localLines = lines.map(function(arr) {
    return arr.slice();
});

The .map method will return a new Array of the return values, which are a slice of each nested Array.


FWIW, here's a shorter version that will work in modern browsers, though I'd probably stick with the first one.

var localLines = lines.map(Array.apply.bind(Array, null));

8 Comments

Thanks mate. Wasn't far off trying this. So new to JS.
You're welcome. Since it seems you're using underscore, you may want to use its map method if you're targeting older browsers.
@JosephSilber: Array is just the new Array constructor. The .apply is the normal Function.prototype.apply. Using .bind(), we're binding the this value of .apply() to the Array function, and the first argument of .apply() to null, so the function returned will effectively do Array.apply(null, ...). Since the first argument passed by .map is each member of the lines array, the call becomes Array.apply(null, ["foo", "bar"]), which is the same as doing Array("foo", "bar"), giving us a new Array with those members.
@JosephSilber: Any function that won't get tripped up by the other arguments passed by .map(). In reality, each call to the callback will look more like Array.apply(null, ["foo", "bar"], 0, lines), where 0 is the current index, and lines is the original Array, but .apply() will ignore those extra args.
Why did @JosephSilber delete all his comments???
|
4

A non-destructive approach to reverse an array in Javascript

ES6

var array = [1,2,3];
array.reduce((ary, ele) => {ary.unshift(ele); return ary}, []);
// => [3,2,1];
// array => [1,2,3];

ES5

array.reduce(function(obj, ele){
  obj.unshift(ele);
  return obj;
},[]);

Comments

1

You can safely (deep) copy a nested array with JSON.parse and JSON.stringify, therefore the reference is not shared. Then destructively reverse the duplicate:

let array1 = [[1, 3], [50, 1]];
let arrayCopy = JSON.parse(JSON.stringify(array1));
arrayCopy.reverse(); //[[50,1],[1,3]]

checkout cloning of arrays for more info

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.