Matt Anderson
Matt Anderson

Reputation: 111

Is there a way to method chain .push and .shift array methods?

Here's my code:

var myArr = [1,2,3,4,5];
function queue(arr, item) {
  return arr.push(item).shift();
}

I'm attempting to create a function queue which takes an "array" and an "item" as arguments. I need to

  1. Add the item onto the end of the array
  2. Remove the first element of the array
  3. Return the element that was removed.

My code is not working. Can you help me figure this out?

Upvotes: 9

Views: 6335

Answers (5)

King Friday
King Friday

Reputation: 26086

Absolutely and Immutably so

push

[1, 2].concat([3])
// [1,2,3]

shift

[1,2,3].filter((e, i, a) => i != 0)
// [2,3]

pop

[1,2,3].filter((e, i, a) => i != a.length - 1)
// [1,2]

unshift

[1,2,3].concat([0]).map((e, i, a) => i == 0 ? a[a.length - 1] : a[i-1])
// [0,1,2,3]

Using the 2nd param index and 3rd param array inside map and filter makes things pretty flexible. You can try more by using that approach.

Another (easier) way but slightly reckless and NOT immutable

push

Array.prototype.pushChain = function(item) {
  this.push(item)
  return this
}
[1,2,3].pushChain(4)
//[1,2,3,4]

Meaning you can use the prototype of an array and use the simpler methods you want to chain but simply return this and you are good but the downside is you could mess up other code relying on the Array to be as it is or possibly overriding some other method you didn't intend.

OR

Another approach is make a JavaScript ES6+ type class like so

class ImmutableChainedArray {
  constructor(arr) {
    this._arr = Array.isArray(arr) ? arr : []
  }
  push(item) {
    this._arr = this._arr.concat([item])
    return this
  }
  pop() {
    this._arr = this._arr
      .filter((e, i, a) => i != a.length - 1)
     return this
  }
  shift() {
    this._arr = this._arr
      .filter((e, i, a) => i != 0)
    return this
  }
  unshift(item) {
    this._arr = this._arr
      .concat([item])
      .map((e, i, a) => i == 0 ? a[a.length - 1] : a[i-1])
    return this
  }
  // the rest of them are easy...

  val() {
    return this._arr
  }
}

then use like

const ica = new ImmutableChainedArray([1])
ica.unshift(0).push(2).shift().pop().val()
// ends up with [1]

Upvotes: 3

AmerllicA
AmerllicA

Reputation: 32572

Actually, all answers are right and I wanna just add another way in ES6:

const Queue = (array, item) => { array.push(item); return array.splice(0,1); }

Or

const Queue = (array, item) => { array.push(item); return array.shift(); }

You shouldn't use concat instead of push because in your case you should mutate your myArr array because it is a queue.

Upvotes: 1

hobberwickey
hobberwickey

Reputation: 6444

There is sort of a hack using concat instead of push

function queue(arr, item) {
  return arr.concat([item]).shift();
}

Should get you the result you want.

Upvotes: 2

Oriol
Oriol

Reputation: 288590

Just don't chain the method calls:

function queue(arr, item) {
  arr.push(item);
  return arr.shift();
}

Or, if you want a single statement,

function queue(arr, item) {
  return arr.push(item), arr.shift();
}

Alternatively, if you are mad enough, you could subclass Array and add a chainable push:

class MyArray extends Array {
  chainablePush(item) {
    this.push(item);
    return this;
  }
}
var myArr = new MyArray(1,2,3);
myArr.chainablePush(4).shift(); // 1
myArr; // MyArray [2,3,4];

Upvotes: 13

Jaromanda X
Jaromanda X

Reputation: 1

because arr.push returns the length of the array, you can't chain the shift like that

simply do this

function queue(arr, item) {
  arr.push(item);
  return arr.shift();
}

Upvotes: 8

Related Questions