Write a function that rotates an array using .pop and .splice - javascript

I need to write a function that takes two arguments. It will modify the array(are) by popping an element and splicing it at the start of the array. It should be repeated num times. My attempt so far:
function rotate(arr, num) {
var i = 0;
while (i<num){
arr.pop();
arr.splice(0, 0, arr.pop());
i++;
}
return arr;
}
console.log(rotate(["Harry","Sarah","Oscar","Tina"],2));

Array::pop() removes and returns the removed element. You need to use it only once.
As #Xufox correctly mentions
Usually this is done with arr.unshift(arr.pop()); I’m not sure why OP needs to use splice here…
function rotate(arr, num) {
var i = 0;
while (i<num){
arr.unshift(arr.pop());
i++;
}
return arr;
}
console.log(rotate(["Harry","Sarah","Oscar","Tina"],2));

popwill remove the last entry of your array and return it. When doing it twice, you loose an entry
function rotate(arr, num) {
var i = 0;
while (i<num){
var x = arr.pop();
arr.splice(0, 0, x);
i++;
}
return arr;
}
console.log(rotate(["Harry","Sarah","Oscar","Tina"],2));

Instead of telling us what the function does right now, would you explain in general terms what the function should do? Or what result do you expect from the array in the example?
I see a couple of things:
In line 4 you are using arr.pop(). This is removing one item from the array and not placing it anywhere. Therefore, your array has one less item.
You are calling arr.pop() one more time so you are removing yet one more item from the array.
Instead of splice(0,0...) you could use unshift(). This will add an item to the beginning of the array. (Oposite of push())
Do you really need to pass and argument that tells how many times should the array rotate? Could you use for your purposes the lenght of the array?

To achieve what you want, why you need pop() and loop, simply twice splice() is enough.
arr.splice(0,0, ...arr.splice(arr.length-num));
function rotate(arr, num) {
arr.splice(0,0, ...arr.splice(arr.length-num));
return arr;
}
var arr =["Harry","Sarah","Oscar","Tina"];
rotate(arr, 2);
console.log(arr);

Related

Have integer added to end of array if larger than rest of integers in array

My function goes through an array to find the lowest index it should be inserted into. I am assuming the array is always sorted. It works unless the integer is larger than the rest of the array integers. At this point, it needs to be added to the end of the array.
I tried to use if else statements and have the number appended with a push but it just goes into a never-ending loop since I will always stay less than arr.length. I tried adding a break after the push inside the else but then, it always appends without inserting into the correct position if there is a place inside the array for it already.
function lowestIndexInsert(num,arr){
for (i = 0; i<arr.length; i++){
if (arr[i]>num){
arr[i]=num;
}
else {
arr.push(num);
break;
}
}
return arr.indexOf(num);
}
lowestIndexInsert(15,[8,25,33,52,70]);// should return 1
lowestIndexInsert(80,[8,25,33,52,70]);// should return 5
You can use splice to insert an element to the array and then instantly break. Once this is done you can catch the final case where i = length and hasn't been inserted yet. If you use 3 arguments such as: .splice(start, deleteCount, insertMe) the function will insert the item at the specific index and delete none. With this you can do:
function lowestIndexInsert(num,arr){
for (i = 0; i<arr.length; i++){
if (arr[i]>num){
arr.splice(i, 0, num);
// Break here to stop the loop after inserting
break;
}
// Perform a final check to see if the item was inserted.
if(i == (arr.length - 1)){
arr.push(num);
}
}
return arr.indexOf(num);
}
lowestIndexInsert(15,[8,25,33,52,70]);// should return 2
lowestIndexInsert(80,[8,25,33,52,70]);// should return 5
If you want to iterate as many times as the original array was long, you have to remember what that length was. That's what variable are for.
Also, you don't know if you need to add to the array until you have finished searching it.
You're pushing inside the loop, so you'll get your new value pushed once for every single number in the array that's greater than the value. That's not what you want.
You can greatly simplify this code, and avoid manual loops altogether:
function lowestIndexInsert(num,arr) {
let index = arr.length;
arr.some((value, i) => {
if (value > num) {
index = i;
return true;
}
return false;
});
arr[index] = num;
}

How can I implement the lodash _.remove function in modern browsers?

I have this code using lodash:
_.remove(this.home.modal.data.subTopics, function (currentObject) {
return currentObject.subTopicId === subTopicToDelete;
});
Can someone give me advice as to how I could do the same using modern browser functions without lodash?
Note it would be okay for the output of the remove to go into another variable.
You could use Array#filter() and negate the filter clause:
this.home.modal.data.subTopics.filter(function (currentObject) {
return currentObject.subTopicId !== subTopicToDelete;
});
This will return an array where subTopicId does not equal subTopicToDelete. It's then up to you to save it in a variable or wherever.
Or, if you want to create a method out of it, you could do:
function remove(array, filterMethod) {
return array.filter(function(){
return !filterMethod.apply(this, arguments);
});
}
Why not have a look at lodash's source code for _.remove?
function remove(array, predicate, thisArg) {
var index = -1,
length = array ? array.length : 0,
result = [];
predicate = getCallback(predicate, thisArg, 3);
while (++index < length) {
var value = array[index];
if (predicate(value, index, array)) {
result.push(value);
splice.call(array, index--, 1);
length--;
}
}
return result;
}
(The getCallback call is not really interesting here, just replace it with a predicate function that returns a boolean value for the given arguments: value, index, array. Not all of them need to be supplied obviously, this is JavaScript after all!)
Lodash uses Array.prototype.splice at the appropriate position, pushing the removed element onto the result array. Then it decreases the current loop index and the saved length by 1 using --, because every time you use .splice, you modify the array directly, for instance:
var arr = ['a', 'b'];
arr.splice(0, 1);
arr[1] // undefined
splice in this context really just the same as Array.prototype.splice. You can as well do array.splice(index--, 1).
A maybe more simple/understandable way is to (for-)loop through the array from the right, starting at array.length - 1 and ending at 0. Then splice every element at the current index, if it passes the predicate function, and push the result value of that operation onto the result array. Return the result array after the loop.
This works the same, because if you start removing elements from the right side, the index of the rest of the looped elements doesn't change. Maybe there are performance advantages to lo-dash's code, but I couldn't tell you that.
You could adapt Array.prototype to suit your needs. Some people don't like this approach, but it can be useful sometimes. In this example I pass in the key and the value I want to amend the array by:
if (!Array.prototype.remove) {
Array.prototype.remove = function (key, value) {
return this.filter(function (el) {
return el[key] !== value;
});
}
}
data.remove('name', 'dan');
DEMO

how do i write iteration inside jquery plugin with array.shift() and pass array to next loop unchanged?

Im writing a jquery plugin which will iterate throw the passed array and recursively call simple function with passed array.shifted,
function test (arr, el){
console.log(el, arr);
if ( arr.length > 0 ) {
arr.shift();
test(arr, el);
}
}
$.fn.someFunc = function( config, cb ){
return this.each(function(i, el){
test(config, i);
})
};
and it works fine if i'm calling someFunc() on jquery with single element selector: $('#singleElement').someFunc(['one','two','tree']), but if i call it on jquery with multiple element selector like $('.class').someFunc(['one','two','tree']) (assuming that i have 2+ divs with class .class) arr object goes to second element already empty.
so does anyone have any idea how to make arr local for each loop and then shift it or better solution for this kind of a problem if i am getting the problem wrong. thnx
Instead of
if (arr.length > 0) {
arr.shift();
test(arr, el);
}
Write
if (arr.length > 0) {
test(arr.slice(1), el);
}
arrays are passed as references, so when you shift element it's shifted from array reference (it's one object).
when calling array.slice it duplicates array sliced in chunks you want, so array is remaining unchanged.
or change
test(config, el);
to
test(config.slice(0), el);
in someFunc.
test Fn will get duplicated array and will shift elements from one reference for each element.

Loop to remove an element in array with multiple occurrences

I want to remove an element in an array with multiple occurrences with a function.
var array=["hello","hello","world",1,"world"];
function removeItem(item){
for(i in array){
if(array[i]==item) array.splice(i,1);
}
}
removeItem("world");
//Return hello,hello,1
removeItem("hello");
//Return hello,world,1,world
This loop doesn't remove the element when it repeats twice in sequence, only removes one of them.
Why?
You have a built in function called filter that filters an array based on a predicate (a condition).
It doesn't alter the original array but returns a new filtered one.
var array=["hello","hello","world",1,"world"];
var filtered = array.filter(function(element) {
return element !== "hello";
}); // filtered contains no occurrences of hello
You can extract it to a function:
function without(array, what){
return array.filter(function(element){
return element !== what;
});
}
However, the original filter seems expressive enough.
Here is a link to its documentation
Your original function has a few issues:
It iterates the array using a for... in loop which has no guarantee on the iteration order. Also, don't use it to iterate through arrays - prefer a normal for... loop or a .forEach
You're iterating an array with an off-by-one error so you're skipping on the next item since you're both removing the element and progressing the array.
That is because the for-loop goes to the next item after the occurrence is deleted, thereby skipping the item directly after that one.
For example, lets assume item1 needs to be deleted in this array (note that <- is the index of the loop):
item1 (<-), item2, item3
after deleting:
item2 (<-), item3
and after index is updated (as the loop was finished)
item2, item3 (<-)
So you can see item2 is skipped and thus not checked!
Therefore you'd need to compensate for this by manually reducing the index by 1, as shown here:
function removeItem(item){
for(var i = 0; i < array.length; i++){
if(array[i]==item) {
array.splice(i,1);
i--; // Prevent skipping an item
}
}
}
Instead of using this for-loop, you can use more 'modern' methods to filter out unwanted items as shown in the other answer by Benjamin.
None of these answers are very optimal. The accepted answer with the filter will result in a new instance of an array. The answer with the second most votes, the for loop that takes a step back on every splice, is unnecessarily complex.
If you want to do the for loop loop approach, just count backward down to 0.
for (var i = array.length - 0; i >= 0; i--) {
if (array[i] === item) {
array.splice(i, 1);
}
}
However, I've used a surprisingly fast method with a while loop and indexOf:
var itemIndex = 0;
while ((itemIndex = valuesArray.indexOf(findItem, itemIndex)) > -1) {
valuesArray.splice(itemIndex, 1);
}
What makes this method not repetitive is that after the any removal, the next search will start at the index of the next element after the removed item. That's because you can pass a starting index into indexOf as the second parameter.
In a jsPerf test case comparing the two above methods and the accepted filter method, the indexOf routinely finished first on Firefox and Chrome, and was second on IE. The filter method was always slower by a wide margin.
Conclusion: Either reverse for loop are a while with indexOf are currently the best methods I can find to remove multiple instances of the same element from an array. Using filter creates a new array and is slower so I would avoid that.
You can use loadash or underscore js in this case
if arr is an array you can remove duplicates by:
var arr = [2,3,4,4,5,5];
arr = _.uniq(arr);
Try to run your code "manually" -
The "hello" are following each other. you remove the first, your array shrinks in one item, and now the index you have follow the next item.
removing "hello""
Start Loop. i=0, array=["hello","hello","world",1,"world"] i is pointing to "hello"
remove first item, i=0 array=["hello","world",1,"world"]
next loop, i=1, array=["hello","world",1,"world"]. second "hello" will not be removed.
Lets look at "world" =
i=2, is pointing to "world" (remove). on next loop the array is:
["hello","hello",1,"world"] and i=3. here went the second "world".
what do you wish to happen? do you want to remove all instances of the item? or only the first one? for first case, the remove should be in
while (array[i] == item) array.splice(i,1);
for second case - return as soon as you had removed item.
Create a set given an array, the original array is unmodified
Demo on Fiddle
var array=["hello","hello","world",1,"world"];
function removeDups(items) {
var i,
setObj = {},
setArray = [];
for (i = 0; i < items.length; i += 1) {
if (!setObj.hasOwnProperty(items[i])) {
setArray.push(items[i]);
setObj[items[i]] = true;
}
}
return setArray;
}
console.log(removeDups(array)); // ["hello", "world", 1]
I must say that my approach does not make use of splice feature and you need another array for this solution as well.
First of all, I guess your way of looping an array is not the right. You are using for in loops which are for objects, not arrays. You'd better use $.each in case you are using jQuery or Array.prototype.forEach if you are using vanila Javascript.
Second, why not creating a new empty array, looping through it and adding only the unique elements to the new array, like this:
FIRST APPROACH (jQuery):
var newArray = [];
$.each(array, function(i, element) {
if ($.inArray(element, newArray) === -1) {
newArray.push(region);
}
});
SECOND APPROACH (Vanila Javascript):
var newArray = [];
array.forEach(function(i, element) {
if (newArray.indexOf(element) === -1) {
newArray.push(region);
}
});
I needed a slight variation of this, the ability to remove 'n' occurrences of an item from an array, so I modified #Veger's answer as:
function removeArrayItemNTimes(arr,toRemove,times){
times = times || 10;
for(var i = 0; i < arr.length; i++){
if(arr[i]==toRemove) {
arr.splice(i,1);
i--; // Prevent skipping an item
times--;
if (times<=0) break;
}
}
return arr;
}
An alternate approach would be to sort the array and then playing around with the indexes of the values.
function(arr) {
var sortedArray = arr.sort();
//In case of numbers, you can use arr.sort(function(a,b) {return a - b;})
for (var i = 0; sortedArray.length; i++) {
if (sortedArray.indexOf(sortedArray[i]) === sortedArray.lastIndexOf(sortedArray[i]))
continue;
else
sortedArray.splice(sortedArray.indexOf(sortedArray[i]), (sortedArray.lastIndexOf(sortedArray[i]) - sortedArray.indexOf(sortedArray[i])));
}
}
You can use the following piece of code to remove multiple occurrences of value val in array arr.
while(arr.indexOf(val)!=-1){
arr.splice(arr.indexOf(val), 1);
}
I thinks this code much simpler to understand and no need to pass manually each element that what we want to remove
ES6 syntax makes our life so simpler, try it out
const removeOccurences = (array)=>{
const newArray= array.filter((e, i ,ar) => !(array.filter((e, i ,ar)=> i !== ar.indexOf(e)).includes(e)))
console.log(newArray) // output [1]
}
removeOccurences(["hello","hello","world",1,"world"])

Removing all items from an array (individually)

I have an array with a finite number of items in it. I want to randomly remove items until all the items have been used once.
Example [1,2,3,4,5]
Random number 5 is used, so I don't want that again.
Random number 2 is used, so I don't want that again.
And so on..
I could have another list of used numbers and check that the new random number is not in it, but that could take a long time when there is only 1 or two numbers left in the array out of 50.
Is there a way to remove an item from an array in javascript? Does it create a new array and would that be inefficient?
Are arrays the wrong way to do this?
EDIT: A few good answers here. I ended up randomizing the array list and then splicing the first item which is the one I took out.
Use the combination of Math.random() and splice():
var arr = [1, 2, 3, 4, 5],
i;
while ( arr.length ) {
i = Math.floor( Math.random() * arr.length );
alert( arr.splice(i, 1) );
}
Live demo: http://jsfiddle.net/simevidas/n2Bmk/
Update: You can use this function to remove a random item from your array:
function popRandomItem(arr) {
return arr.length ?
arr.splice(Math.floor(Math.random() * arr.length), 1)[0] : null;
}
So, if you have an array x, then popRandomItem(x) will remove a random item from that array and return that item. (If x is an empty array, the function will return null.)
Live demo: https://jsbin.com/wetumec/edit?js,console
You can use splice() to remove array elements.
Update
The function below lets you specify an upper and lower bound, and calling the resulting returned function will return a random number until the pool is empty, in which case it will return false (make sure you detect this with getRandom() === false).
var getRandomNumberOnce = function(lower, upper) {
var pool = [];
for (var i = lower; i <= upper; i++) {
pool.push(i);
}
return function() {
if (pool.length == 0) {
return false;
}
var randomIndex = Math.floor(Math.random() * pool.length ),
randomNumber = pool[randomIndex];
pool.splice(randomIndex, 1);
return randomNumber;
}
}
jsFiddle.
Usage
var myRandom = getRandomNumberOnce(0, 50);
myRandom(); // 4 (guaranteed to be random) :P http://xkcd.com/221/
I understand you're asking about removing elements but I'm going to go ahead and suggest an alternative way. This way does the same thing you want (getting a random element only once) but doesn't involve removing elements - well, it doesn't have to.
Essentially, randomise the order of your array rather than looking for random elements. Then work your way through the array for the random element you need. Your first random element will be at the 0 index, second random element will be at 1 index, etc.
var array = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14];
array.sort(function(){ return (Math.round(Math.random())-0.5); });
for(var i=0;i<array.length;i++){
$("#list").append('<li>Random element ' + i + ': ' +array[i]);
}
Example: http://jsfiddle.net/jonathon/Re4HK/
Another question talks about randomising a JavaScript array but I just used a basic random sort as it works to illustrate the idea. You might want to look at that if you're concerned about how random your array is.
Sometimes you want a random item and don't
care if it is repeated once in a while.
Other times you want to quit when the aray is empty,
and see no repeats.
Array.prototype.getRandom= function(cut){
var i= Math.floor(Math.random()*this.length);
return cut? this.splice(i, 1): this[i];
}

Categories

Resources