Jonas Lu
Jonas Lu

Reputation: 181

javascript array shifting one object into front

say I have an array

const cityList = [
 {id: 1, name: 'Dallas'},
 {id: 2, name: 'Houston'},
 {id: 3, name: 'San Antonio'},
 {id: 4, name: 'Austin'},
]

I want to select the Houston that object and move to the top of the array.

I came up with

cityList.forEach(city => {
  if(city.name === 'Houston') {
    cityList.splice(...);   // then do a unshift() to top here...
  }
});

but I am not sure this is the most efficient way to do cuz I want to cut the whole object and move to the top.

Upvotes: 0

Views: 54

Answers (3)

user12407908
user12407908

Reputation:

I would not use .forEach() to iterate, or .splice() for the removal.

Instead, I'd use .findIndex() to get the index of the object, and then .copyWithin() to shift the elements over before putting the targeted object at the first index.

const cityList = [
 {id: 1, name: 'Dallas'},
 {id: 2, name: 'Houston'},
 {id: 3, name: 'San Antonio'},
 {id: 4, name: 'Austin'},
];

function cityToFront(city) {
  const idx = cityList.findIndex(o => o.name === city);
  if (idx === -1) return;
  
  const obj = cityList[idx];      // grab the object
  cityList.copyWithin(1, 0, idx); // shift others over one index
  cityList[0] = obj;              // assign the object to the start
  
  // You can do this in one line with destructuring assignment
  // [cityList[0], ] = [cityList[idx], cityList.copyWithin(1, 0, idx)];
  
  // It evaluates and holds the value of cityList[idx] before
  // doing the copyWithin()
}

cityToFront("Houston");

console.log(cityList);

This lets you accomplish the gory details using lower level implementations, and it does so without allocating any temporary arrays.

Upvotes: 2

Scott Sauyet
Scott Sauyet

Reputation: 50787

I prefer to write code that does not mutate the input data, returning appropriate copies as necessary. I also prefer solving problems like this slightly more abstractly. Here is a function which does both, using .slice instead of .splice and accepting an arbitrary predicate to match:

const moveToFront = (pred = () => false) =>  (xs = [], index = xs .findIndex (pred)) => 
  index > -1 
    ? [xs [index], ... xs .slice (0, index), ...xs .slice (index)]
    : [...xs]


const cityList = [{id: 1, name: 'Dallas'}, {id: 2, name: 'Houston'}, {id: 3, name: 'San Antonio'}, {id: 4, name: 'Austin'}]

console .log (moveToFront (({name}) => name == 'Houston') (cityList))

If we now want something which takes a city name and a list of cities, we can partially apply the above version like this:

const moveCityToFront = (name) => 
  moveToFront (({name: n}) => name == n)

moveCityToFront ('Houston') (cityList)
//=> [{id: 2, name: 'Houston}, {id: 1, name: 'Dallas'}, ...]

Upvotes: 0

Derek Wang
Derek Wang

Reputation: 10193

You can simply move one object from one position to another position using `Array.prototype.splice

const cityList = [
  {id: 1, name: 'Dallas'},
  {id: 2, name: 'Houston'},
  {id: 3, name: 'San Antonio'},
  {id: 4, name: 'Austin'},
];

const index = cityList.findIndex(({ name }) => name === 'Houston');
if (index >= 0) {
  cityList.splice(0, 0, cityList.splice(index, 1)[0]);
}
console.log(cityList);

Upvotes: 3

Related Questions