Why .splice() method deletes elements of different indexes? - javascript

This is my first question on stackoverflow, I am new :) learning JS. I have a question. I wrote this function:
function inverseSlice(items, a, b) {
return items.splice(a, b);
}
inverseSlice([1, 2, 3, 4, 5, 6], 2, 4)
(4) [3, 4, 5, 6]
Why this function returns last 4 digits, when according to docs on MDN (which I read 10 times already :P) splice() method should remove here only 2 middle ones (3, 4)? It should return [1, 2, 5, 6]. Am I right? Thank You for all Your help :)

It's doing exactly what it advertises, it "returns an array containing the deleted elements."
function inverseSlice(items, a, b) {
return items.splice(a, b);
}
let array = [1, 2, 3, 4, 5, 6, 7, 8];
// Deletes 4 entries starting at index 2,
// or in other words [3,4,5,6] are snipped
inverseSlice(array, 2, 4);
console.log(array);
Unless you keep a reference to the array you're passing in you'll never observe anything about how it ends up, you'll only get the deleted elements.

splice will
Mutate the original array: remove N items, where N is the third parameter, starting from the start index (first parameter) to the number specified (so here, it'll remove indicies 2 through 5 from the array; indicies 2, 3, 4, and 5, a total of 4 get removed)
Return the removed elements - so, here, that's [3, 4, 5, 6].
The original array is now [1, 2], but you're logging what was returned by .splice, not the original array.
If you wanted [1, 2, 5, 6], you'd want to specify 2 for the 3rd argument (2 items to remove), and then log the original array:
function inverseSlice(items, a, b) {
return items.splice(a, b);
}
const arr = [1, 2, 3, 4, 5, 6];
const removedItems = inverseSlice(arr, 2, 2);
console.log(arr);
console.log(removedItems);

What you are confused about is the arguments to splice, The two arguments that you pass to splice are not the start and end index but the start index and the count of items to be deleted.
Hence in your example it deleted items from 2 to 5 index and returned you the resultant array i.e [3, 4, 5, 6]
As per the docs:
Syntax:
let arrDeletedItems = arr.splice(start[, deleteCount[, item1[, item2[, ...]]]])
Parameters
Start : The index at which to start changing the array.
deleteCount: n integer indicating the number of elements in the array to remove from start.
item1, item2, ... : The elements to add to the array, beginning from start. If you do not specify any elements, splice() will only remove
elements from the array.

Related

Splitting and Adding Arrays

Trying to remove the last two elements then add a 2 to the end of the array. But, keep getting an error. First test works then my second fails.
var userArray = [4, 2, 8, 5, 0, 1, 6]; // Tests may use different array values
/* Your solution goes here */
userArray.splice(5, 2, 2);
CORRECT: Testing the final value of userArray when the initial array is [4, 2, 8, 5, 0, 1, 6]
Yours
4,2,8,5,0,2
INCORRECT: Testing the final value of userArray when the initial array is [-5, 3]
Yours and expected differ. See highlights below.
Yours
-5,3,2
Expected
2
// Tests may use different array values
Your answer should be: userArray.splice(userArray.length-2, 2, 2);
var arr = [1, 2, 3, 4, 5, 3, 1]
arr.splice(-2, 2, 2)
console.log(arr)
tried this and workd.. had to ensure the array had more than 2 elements first..
function trimLast2elements(ar){
if(ar.length > 2){
index = ar.length - 2 //get first index of last 2 elements..
ar.splice(index, 2, 2);
return ar; //return array.
}else{
//function if array count is less
}
}
apply function when needed.

Spread Syntax with Map and Filter

I found this interesting problem and wanted to share with you guys.
The question is :
[...[0,1,...[-1,0,1].map((x)=> x+1)].filter((x)=>x)),7]
I easily solved the first section upto the filter as [0,1,(-1+1),(0+1),(1+1)] = [0,1,0,1,2].
I was surprised to find the 7 hanging at the end. I thought it was some typo but copying the problem into the console gave me [1,1,2,7]. I couldn't quite understand 2 things.
why were the 0's left out of filter
what's the 7 doing there
The first operation here is Array#map [-1, 0, 1].map(x => x + 1) which basically adds 1 to each element, returning [0, 1, 2] array.
Next one is Array#filter operation, [0, 1, ...[0, 1, 2]].filter(x => x) which actually returns a new array, without every falsy value (false, 0, undefined, null, "") out of the array.
The last operation looks like [...[1, 1, 2], 7] and gets rid of the nested array with the spread operator returning [1, 1, 2, 7].
[...[0,1,...[-1,0,1].map((x)=> x+1)].filter((x)=>x),7] broken down:
[-1,0,1].map((x)=> x+1) // [0,1,2]
[0,1,...[-1,0,1].map((x)=> x+1)] // [0,1,0,1,2]
[0,1,...[-1,0,1].map((x)=> x+1)].filter((x)=>x) // [1,1,2]
[...[0,1,...[-1,0,1].map((x)=> x+1)].filter((x)=>x),7] // [1,1,2,7]
this part [-1,0,1].map((x)=> x+1) results in this list [0,1,2] then this part [0,1,...[-1,0,1].map((x)=> x+1)] results in [0,1,1,2] which after the filter part drops the 0 so it results into [1,1,2], finally the last element of the list is 7. So, altogether the result is [1,1,2,7]
The code evaluates in the following steps:
[...[0, 1, ...[-1, 0, 1].map((x)=>x+1)].filter((x)=>x)), 7] // map
[...[0, 1, ...[(x=>x+1)(-1), (x=>x+1)(0), (x=>x+1)(1)]].filter((x)=>x)), 7] // function application
[...[0, 1, ...[0, 1, 2]].filter((x)=>x)), 7] // spread
[...[0, 1, 0, 1, 2].filter((x)=>x)), 7] // filter
[...[...(x=>x)(0)?[0]:[], ...(x=>x)(1)?[1]:[], ...(x=>x)(0)?[0]:[], ...(x=>x)(1)?[1]:[], ...(x=>x)(2)?[2]:[]], 7] // function application
[...[...0?[0]:[], ...1?[1]:[], ...0?[0]:[], ...1?[1]:[], ...2?[2]:[]], 7] // conditional
[...[...[], ...[1], ...[], ...[1], ...[2]], 7] // spread (from filter)
[...[1, 1, 2], 7] // spread
[1, 1, 2, 7]

How to iterate over array in reverse order with Lodash?

I want to iterate over an array in reverse order using Lodash. Is that possible?
My code looks like below.
var array = [1, 2, 3, 4, 5];
_.each(array, function(i) {
_.remove(array, i);
});
When I do _.pullAt(array, 0) new array is [2, 3, 4, 5]. All array elements shifted to left by 1 position, and current index is pointing to element 3. After next iteration, 3 will get deleted and then 5. After 3rd iteration array contains [2, 4] which I couldn't delete.
If I iterate over the array in reverse order, then this problem won't arise. In Lodash, can I iterate over an array in reverse order?
You can use _.reverse available in version 4:
var array = [1, 2, 3, 4, 5];
array = _.reverse(array)
console.log(array)
//5, 4, 3, 2, 1
See How do I empty an array in JavaScript? if you only want that and choose your weapon.
Otherwise, strictly answering the question, to iterate the indices from the length of the array to zero, you could use the "down-to" --> operator1. But that's not really necessary, even underscore isn't necessary in this case as the .pop function is enough.
var arr = [1, 2, 3, 4, 5],
index = arr.length;
while (index --> 0) {
console.log(index);
arr.pop();
}
console.log(arr);
If you're using Lodash like the functions referenced in the question seem to indicate, you could use _.eachRight.
var arr = [1, 2, 3, 4, 5];
_.eachRight(arr, function(value) {
console.log(value);
arr.pop();
});
console.log(arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
1 The down-to operator doesn't exist and is only a -- decrement followed by a > comparison.

After creating a random javaScript-array with recurring integers - avoid identical integers side by side

have anybody any suggestion to "deal" a array after filling it randomly with recurring integers?
here is a easy example (3 x integer-group: 1,2,3,4):
array[1,2,3,4,4,2,3,1,1,4,3,2];
is there a way with a special function, to "rearrange" the array, by avoiding the same integers side by side.
this would be OK (no immediate neighbor is identical):
array[1,2,1,2,1,3,4,3,4,3,4,2];
those are not:
array[4,4,4,1,2,3,3,2,1,1,2,3];
array[1,2,3,2,1,3,3,4,4,1,2,4];
in my case the array could have 25 to 30 times the same integer-group.
hopefully I'm declaring comprehensible - so, you understanding my problem!
Thank you in advance for your efforts
FerO
Edited for clarity:
All integers must be conserved (not deleted) and the integers could be between 0 and 99!
changed "clean" to "rearrange"
Okay, now that I understand what you're after better - here you are. First, a caveat: there are arrays for which this is impossible. For instance, any array in which more than half the elements have the same value cannot be shuffled to keep those values away from each other.
That said:
var insert = function(val,arr) {
if (arr.length > 1) {
for (var i=1;i<arr.length;i++) {
if (arr[i-1] !=val && arr[i] != val) {
arr.splice(i,0,val);
return arr;
}
}
}
arr.splice(0,0,val);
return arr;
}
var shuffle = function(arr) {
return arr.reduce(function(p,c,i,a) {
return insert(c,p);
}, []);
}
shuffle() returns a new array built by shuffling the values of the input array; if you'd rather have them shuffled 'in place' by mutating the input array, that's easy enough to do. There may exist theoretically-shuffleable arrays which this algorithm fails for. I haven't found any in brief testing, but I also haven't proven they don't exist.
The algorithm here is:
Start with an empty 'destination' array.
For each element in the input array, traverse the destination array and insert it into the first position found where it does not equal either of its neighbors.
If no such position is found, stick it at the front.
(This would perform slightly better if it weren't ignoring the possibility of putting things in position 0 right off)
shuffle([4,4,4,3,3,3,2,2,2,1,1,1,1]) = [3, 1, 2, 1, 4, 1, 2, 1, 3, 2, 4, 3, 4]
shuffle([1,2,3,4,4,2,3,1,1,4,3,2,2]) = [2, 3, 2, 4, 2, 1, 3, 1, 4, 2, 3, 4, 1]
shuffle([1,1,1,1,1,1,1,2,2,2,2,2,2,2]) = [2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1]
JSfiddle
You can use Array.prototype.filter() to remove values that are adjacent to identical values.
var myArray = [1, 2, 3, 4, 4, 2, 3, 1, 1, 4, 3, 2];
var deduped = myArray.filter(function (value, index, collection) {
return value !== collection[index+1];
});
// deduped is now [1, 2, 3, 4, 2, 3, 1, 4, 3, 2]

Javascript:: Find differences between array that contains duplicated values to a unique array of that array

I found many posts on stack overflow about that similar subject but none of them solve this issue here.
<script>
//Array GanginaA contains duplicated values.
//Array GanginaB contains only unique values that have been fetched from GanginaA
GanginaA=[0,1,2,3,4,5,5,6,7,8,9,9];
GanginaB=[0,1,2,3,4,5,6,7,8,9];
var hezi=<!--The Magic Goes Here-->
console.log(hezi);
/*
* Expected Output:
* 5,9
*/
</script>
GanginaA will always be longer or identical to GanginaB so there is no reason to calculate by the value of the longer array length.
GanginaB will always contains unique values that taken from GanginaA so it will always be the shorter array length or identical to GanginaA array.
Now it makes it a lot easier to find doubles.
You can use filter to get the elements like below
GanginaA = [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9];
GanginaB = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var hezi = GanginaB.filter(function (item, index) {
return GanginaA.indexOf(item) !== GanginaA.lastIndexOf(item)
});
console.log(hezi.join(" , ")); // 5, 9
the easier I can think of :
var hezi=[];
for (var i=0;i<GanginaA.length;i++){
hezi[GanginaA[i]] = GanginaA[i];
hezi[GanginaB[i]] = GanginaB[i];
}
hezi = hezi.filter (function(el){return el!=undefined;});
does everything in O(n) actions and not O(n^2)
Javascript's objects have hashmap like behaviour, so you can use them kind of like a set. If you iterate over all the values and set them to be keys within an object, you can use the Object.keys method to get an array of unique values out.
function uniqueValues() {
var unique = {};
[].forEach.call(arguments, function(array) {
array.forEach(function(value) {
unique[value] = true;
});
});
return Object.keys(unique);
};
This function will return the unique elements in any number of arrays, passed as arguments.
uniqueValues([1, 2, 3], [ 1, 1, 1], [2, 2, 2], [3, 3, 3]); // [ 1, 2 3 ]
One drawback to this method is that Javascript coerces all keys to strings, you can turn them back into numbers by changing the return statement to:
return Object.keys(unique).map(Number);

Categories