4

I'm trying to swap 2 elements within an array in a functional way in javascript (es6)

let arr = [1,2,3,4,5,6]
let result = swap(arr, 1, 2) // input: array, first element, second element
// result=[1,3,2,4,5,6]

The only way I could think about is:

const swap = (arr, a, b) => 
            arr.map( (curr,i) => i === a ? arr[b] : curr )
               .map( (curr,i) => i === b ? arr[a] : curr )

But this code runs twice over the array, and not readable at all. Any suggestions for a nice clean functional code?

Thanks.

3
  • Possible duplicate of Swapping two items in a javascript array Commented Feb 15, 2017 at 20:05
  • Is expected result a new array or swap of elements at original array? Commented Feb 15, 2017 at 20:07
  • ES2023 Array Method with() you can do it in one line: arr.with(a, arr[b]).with(b, arr[a]) see my answer with an example! Commented Jun 11, 2023 at 11:03

7 Answers 7

10

Short and reliable but admittedly hard to read:

const swap = (x, y) => ([...xs]) => xs.length > 1
 ? ([xs[x], xs[y]] = [xs[y], xs[x]], xs)
 : xs;

const xs = [1,2,3,4,5];

const swap12 = swap(1, 2);

console.log(
  swap12(xs),
  "exception (one element):",
  swap12([1]),
  "exception (empty list):",
  swap12([])
);

Sign up to request clarification or add additional context in comments.

2 Comments

Looks great!, not functional though. The core working of this approach relies on mutation
Local mutations are fine. This is Javascript!
6

One 'map' would do it also:

function swap(arr, a, b) {
  return arr.map((current, idx) => {
    if (idx === a) return arr[b]
    if (idx === b) return arr[a]
    return current
  });
}

1 Comment

the stacked ternary makes it a bit unpalatable but it's a nice implementation – note, users should take proper care to validate the indices are in range
4

How about the good ol'

const a = [1,2,3,4,5]

const swap = (start, end, arr) =>
  [].concat(
    arr.slice(0, start), 
    arr.slice(end,end+1), 
    arr.slice(start+1,end), 
    arr.slice(start,start+1)
  )
  
console.log(swap(2, 4, a))

Purely functional, readable, albeit a bit long

1 Comment

I would not recommend this, as slice and concat are expensive to run compared to the cost of swapping two items in an array in place with a placeholder variable, where no additional arrays are created. This would create five arrays during the course of a single swap, not to mention the time complexity of indexing each array.
1

You can use destructuring assignment to swap indexes of an array. If expected result is new array, call Array.prototype.slice() on array passed to swap(), else omit let copy = _arr.slice(0) and reference _arr arr destructuing assignment.

let arr = [1,2,3,4,5,6];
let swap = (_arr, a, b) => {
  let copy = _arr.slice(0);
  [copy[a], copy[b]] = [copy[b], copy[a]];
  return copy
};
let result = swap(arr, 1, 2); 
console.log(result, arr);

1 Comment

If expected result is original array elements to be changed .slice() can be removed let swap = (arr, a, b) => ([arr[a], arr[b]] = [arr[b], arr[a]]) && arr;
0

What a fun little problem – care should be taken to ensure that a and b are valid indices on xs, but I'll leave that up to you.

const swap = (a,b) => (arr) => {
  const aux = (i, [x, ...xs]) => {
    if (x === undefined)
      return []
    else if (i === a)
      return [arr[b], ...aux(i + 1, xs)]
    else if (i === b)
      return [arr[a], ...aux(i + 1, xs)]
    else
      return [x, ...aux(i + 1, xs)]
  }
  return aux (0, arr)
}


let xs = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

// same index doesn't matter
console.log(swap(0,0) (xs)) // [a, b, c, d, e, f, g]

// order doesn't matter
console.log(swap(0,1) (xs)) // [b, a, c, d, e, f, g]
console.log(swap(1,0) (xs)) // [b, a, c, d, e, f, g]

// more tests
console.log(swap(1,3) (xs)) // [a, c, d, b, e, f, g]
console.log(swap(0,6) (xs)) // [g, b, c, d, e, f, a]
console.log(swap(5,6) (xs)) // [a, b, c, d, e, g, f]

// don't fuck it up
console.log(swap(7,3) (xs)) // [a, b, c, undefined, e, f, g]

// empty list doesn't matter
console.log(swap(3,2) ([])) // []

Comments

0

ES2023 Array Method with():

The with() method of Array instances is the copying version of using the bracket notation to change the value of a given index. It returns a new array with the element at the given index replaced with the given value.

let arr = [1,2,3,4,5,6]
function swap(arr, x, y){
  return arr.with(x, arr[y]).with(y, arr[x]);
}
let result = swap(arr, 1, 2)
console.log(result); //[1,3,2,4,5,6]

PS: with() method is supported nearly by all browsers and on Node.js version 20+.
see browser compatibility

Comments

-1

Returns new Array (Function-Programming):

const swap = (arr, a, b)=> { let copy = arr.slice(0); copy[b] = [copy[a], copy[a] = copy[b]][0]; return copy; }

Manipulate the input Array (Non Function-Programming):

const swap = (arr, a, b)=> { arr[b] = [arr[a], arr[a] = arr[b]][0]; return arr; }

1 Comment

mutates arr – not really in the spirit of functional programming

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.