Reputation: 181
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
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
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
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