How to splice multiple array elements and insert accordingly? - javascript

const data = response.data
console.log(data)
const temp = data.ssps_with_scated.splice(5, 1)(1, 3)[0]
data.ps_with_ed.splice(2, 1, 0, temp)
i am trying to achieve finally i got it. But issue is, i cant expect the array value same all the time. So i have decided to re-arrange the array values based on the ID.

Well,
splice(7,1)(21,3)
This code will cause an error. Since Array.prototpy.slice returns a new array.
It would be the same if you would do this:
const a = [1,2,3]
const b = a.splice(1,1);
b(2,1) // b.splice(...) is not a function
EDITED:
Maybe there is a faster/better solution but...
You can make it more general but for your case only:
const array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21];
const first = array[7];
const second = array[21];
// Add elements on certain indices in array (second and third)
array.splice(2, 0, first, second)
// Remove first from the array (index is 7 + 2 because we added 2 elements)
array.splice(9, 1)
// Remove 21 from the array (index is 22 - 1 because we added 2 elements and removed 1, not: number 21 is on index 22)
array.splice(21, 1);

data shouldn't be a const since the value is getting updated. Splice can also only be called on one array at a time. If you need to call it on multiple arrays, create a loop or iterate over them.
If you want to inject the current value of the 7th position into the 2nd position... you'd need to do something like...
array.splice(2, 0, array[7])

Related

How to cycle through an array of values to optimize number of calls to a function?

I have an array of rows from a Google Spreadsheet interspersed with numbers between the bounds of 1 and 800:
var rowPositions = [1,3,4,5,9,10,11,12...795,799,800]
And, for efficiency's sake, I need to make an API call to the function deleteRows, which accepts two parameters:
deleteRows(positionOfFirstRow, howManyRowsShouldBeDeletedStartingFromFirstRow)
Google Documentation for deleteRows.
How can I create a function in Javascript that calls deleteRows a minimal number of times for a given array? IE, using the aforementioned array as an example, the function calls deleteRows to remove the row at position 1, then calls it again to delete 3,4,5, then again to delete 10,11,12, etc...?
In other words, how can I transform that rowPositions array into a two-dimensional one, ex.:
var 2DrowPositions = [[1,1],[3,2],[5,1],[9,4]]
which I can then use to call the deleteRows function once per provided coordinate.
If you are given an array of items to delete like [1, 3, 4, 5, 7, 8, 9, 15, 18, 19, 20, 23] you can step through that array and look for consecutive numbers. Keep track of how many consecutive numbers you see and when you hit a non-consecutive number, save the old one and start again.
Here's one way to do that, which is reasonably easy to read:
let del = [1, 3, 4, 5, 7, 8, 9, 15, 18, 19, 20, 23]
let res = []
let curr = {start: del[0], count: 0}
del.forEach((item, i, arr) => {
if (i === 0 || arr[i] === 1 + arr[i-1]) curr.count++
else {
res.push(curr)
curr = {start: arr[i], count:1}
}
})
res.push(curr)
console.log(res)
This will return an array of objects of the form {start, count} which you can use in your function with something like:
res.forEach(r => deleteRows(r.start, r.count))

Filter and map in JavaScript

I'm doing "experiments" on a little example to understand the use of filter() and map() in JavaScript, and I have a question, based on the following code.
var numbers = [1, 4, 9, 25, 36, 49];
var roots = numbers.filter(function() {
for (i = 0; i < numbers.length; i++) {
if (numbers[i] > 10) {
var index = numbers.indexOf(numbers[i]);
numbers.splice(index, 1);
}
}
return numbers;
}).map(Math.sqrt);
console.log(numbers);
// -> [1, 4, 9]
console.log(roots);
// -> [1, 2, 3]
Why when I put numbers[i] > 10 as a condition the output is correct, whereas if I put numbers[i] < 10 the outcome is the following
console.log(numbers);
// -> [25, 36, 49]
console.log(roots);
// -> [1, 5, 7]
Where the numbers array is correct, but the roots array is messed up?
Your filter function is mutating the numbers array on which its operating; it should just return true or false depending on whether you want the item in the filtered results or not. For example
var roots = numbers.filter(function(n) {
return n > 10;
}).map(Math.sqrt);
In this case numbers is never changed, but roots contains all elements in numbers that are greater than 10.
example fiddle
You are using filter but inside the callback, you are doing your own filter ... which I doubt is intentional. If you break down what your code is doing conversationally, it is basically "for each element in the array, iterate through the entire array (for loop) and in that loop iterate through the entire array again (indexOf)...". At this point you can probably determine something is wrong. Also Array.splice mutates the original array which is usually undesirable.
Here is an example of how you might want to use filter and map
var numbers = [1, 4, 9, 25, 36, 49];
// get numbers greater than 10
numbers.filter(n => n > 10)
// => [25, 36, 49]
// get numbers greater than 10 and take the square root of each number
numbers.filter(n => n > 10).map(Math.sqrt)
// => [5, 6, 7]
Note that these methods are chainable but never mutate the original array. This gives you a great amount of flexibility for performing array computations.
This code is not doing what you think it's doing. It'll be acting very strangely because you're mutating the numbers array as you go along in the for loop.
The correct use of filter is to return true/false for each value, not return a new array. Return true to keep an element, false to remove it.
This is what you're after:
var numbers = [1, 4, 9, 25, 36, 49];
// notice "number" is taken as an argument
var roots = numbers.filter(function(number) {
// return true to include this number, false to reject it
return number < 10;
}).map(Math.sqrt);
console.log(numbers);
// NOTE: has not been changed
// -> [1, 4, 9, 25, 36, 49]
console.log(roots);
// -> [1, 2, 3]
To get an understanding of where your results are coming from, let's walk through each iteration of your code:
filter will run for each element of the array. the for loop will then go through and modify the array.
for number > 10
filter: value of 1
for the first 3 iterations of the for loop, nothing happens, then:
i = 3, so numbers[3] = 25. this passes the condition in your for loop, causing the splice, which will change numbers to [1, 4, 9, 36, 49]
this is where it gets weird #1
In the next iteration of the for loop, i will be 4, but the array has been changed. You may expect the value of 36 to be checked next, but because the array has been modified, and 36 is now in the place of 25, it will be missed. The next value to be checked is in fact 49. Similar reasoning shows that 49 will also be removed.
When the for loop is complete, you are left with numbers = [1, 4, 9, 36]
You then return numbers, which is truthy, which filter interprets as an instruction to keep 1 in the array.
filter: values 4, and 9
The same reasoning can be followed to show that the values of 4 and 9 will remain in the numbers array, and 36 will be removed.
Now, because 25, 36, and 49 have been removed from the array, filter has completed its job, leaving [1, 4, 9] to be passed to map giving [1, 2, 3].
Result
It's actually provided the inverse of the correct answer.
for number < 10
This is where it get really weird.
filter: value of 1
the for loop will remove 1, skip 4 (since it now takes the place of 1), remove 9 (which is in place of 4), skip 25, and keep the rest. This returns a value of [4, 25, 36, 49], which is truthy, and intepreted as keeping 1.
result of filter so far is [1].
filter: value of 25 (since it's now in the 2nd position in the array as 1 was removed)
the for loop will remove the 4, skip 25, and keep the rest. This returns a value of [25, 36, 49], which is truthy, so interpreted as keeping 25.
result of the filter so far is now [1, 25]
filter: value of 49 (since it's now in the 3rd position in the array as 1, 4, and 9 have been removed)
the for loop will keep all of the values since they're all greater than 10, meaning that the return value will be [25, 36, 49], which is truthy, which means that 49 is kept.
result of the filter will be [1, 25, 49], mapped with Math.sqrt is [1, 5, 7]
Result
0_o
Conclusion
Never, ever modify an array as you're looping or using array functions on it.

JavaScript -- Unable to understand Array.Map & Array.reduce

I have been working on a problem on FCC (Free code camp) which requires to scan a 2D array and find largest element from each 1D array and put the result into a 1D array. I came across this solution on GitHub was unable to understand it.
function largestOfFour(arr) {
return arr.map(function(group){
return group.reduce(function(prev, current) {
return (current > prev) ? current : prev;
}, 0);
});
}
largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);
OUTPUT IS [5, 27, 39, 1001]
My console.log(arr) gave me: 4,5,1,3,13,27,18,26,32,35,37,39,1000,1001,857,1
How did that 2D array get converted to 1D array when passed as a function parameter?
My console.log(group) gave me: 4,5,1,3 (first time), 13,27,18,26 (second time), 32, 35, 37, 39 (third time) and 1000, 1001, 857, 1 (fourth time).
How was the anonymous function able to take the parameter group as the individual 1D arrays inside the 2D.
Can someone please help.
When you use Array.map it will process each element within the array for example.
[1, 2, 3, 4].map(function (item) { return item; } );
Will just return a new array with [1, 2, 3, 4], but say we double each value we could do it like this.
[1, 2, 3, 4].map(function (item) { return 2 * item; });
Which returns [2, 4, 6, 8] back.
So in your example you have a 2 dimensional array. The Array.map works on the first level. So in each iteration the group is
1st -> [4, 5, 1, 3]
2nd -> [13, 27, 18, 26]
3rd -> [32, 35, 37, 39]
4th -> [1000, 1001, 857, 1]
So the 1st to 4th will then be passed into the Array.reduce function. Reduce just returns a single value based on the array passed in, or better put
The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
What is happening in the reduce here is storing the maximum value, it begins with 0, and on the first iteration compares with the value 4. As 4 is larger than 0 it is stored and becomes our new max. It then tests against 5 and as 5 is bigger than 4 it stores that as the new max, and so on.
Once it finishes going through it produces a maximum for that array and gives a Number as the result. So now the first iteration of the map which contained an array is changed to a Number, in this case the first item of the Array produced by Array.map should be 5.
The final output I suspect would be
[5, 27, 39, 1001]
Well the array.map() returns a new array by changing the values of the array you pass to it, in this case we're returning a function itself (array.reduce).
arr.map(function(group))
arr.map takes in a 2D array called 'group' and reads each value inside it, in this case another array. So on the first run of 'map' the first array is [4, 5, 1, 3], we call reduce on it.
group.reduce(function(prev, current)
On the first run of 'reduce' we have prev = 4 and current = 5 ("it starts on second value"), then in:
return (current > prev) ? current : prev;
it asks is 5 bigger than 4?, if so return 5 else return 4. So it returns 5. 5 then is passed into 'prev' for the next run of 'reduce' we have prev = 5 (from last run) and current = 1.
return (1 > 5) ? 1 : 5;
It returns 5 since it's bigger than 1.
return (3 > 5) ? 3 : 5;
It returns 5 since it's bigger than 3. end of group.reduce(), the final returned value '5' is returned to arr.map(), the entire first array [4, 5, 1, 3] is replaced by a single value '5'. next run of arr.map() starts with the second array [13, 27, 18, 26].
I actually did that question on freecodecamp, and I didn't have to use map or reduce. I just read through using "double for loop / array.push / returning the array", although "map / reduce" is a lot cleaner and probably a better way of doing it. Hope that explains it

Why doesn't this code loop through all properties of an object?

Here is a little code snippet:
cards = [ 4, 10, 3, 12, 10, 13, 12 ];
suits = [ 1, 64, 8, 8, 1, 1, 32 ];
var o = {}, keyCount = 0, j;
for (i = 0; i < cards.length; i++) {
e = cards[i] + suits[i];
o[e] = 1
}
for (j in o) {
if (o.hasOwnProperty(j)) {
keyCount++;
}
}
After some debugging I found out that when I iterate through all the properties in the 'o' object (the second loop) the loop only executes 6 times instead of 7.
This is despite adding 7 properties to the 'o' object in the first loop.
Why is this? I have added 7 properties in the first loop so why does the second loop only execute 6 times?
The reason is not because the number 12 is in the cards array twice like Pointy said in the comments. He said that 2 properties cannot have the same value which helped me understand. I am saying that e = cards[i] + suits[i]; It just so happens to be that sometimes these 2 values added together sometimes sum to the same answer. eg in this example 3 + 8 = 11 and 10 + 1 also = 11
Javascript object cannot have duplicate key & above snippet is violating that, this is because 3+8 & 10+1 both equals to 11. It such scenerios it will take up the most recent value.So key need to be unique. Therefore change the integer to produce a different sum value.
cards = [ 4, 10, 3, 12, 11, 13, 12 ];
suits = [ 1, 64, 8, 8, 1, 1, 32 ];
WORKING COPY
Well, as most people have noticed, you have duplicates in your object. If you want to work with your current input data, try concatenating the numbers as strings instead of adding them - this will give you a larger set of possible values. Something like
e = cards[i]+":"+suits[i];
So you'll have keys of the form "4:1", "10:64" in your object. This is nice because you can also split them up to get the initial values again if you need them later.

Pick random and remove from collection using underscore

I've got a collection of 20 results (objects), and what I'd like to do when a button is clicked is to:
a) Pick a random object from this collection/array
b) When the button is pressed again - I don't want that object re-picked until the collection is exhausted (i.e. until the 20 items are shown)
I thought of just splicing out the index of that collection, but I'm hoping for a cleaner way using Underscore.js
EXAMPLE:
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11...]
var getRand = _.random(0, data.length);
==> 3
Next time I press the button, I don't want the result "3" to re-appear as it's been used
I hope this makes sense
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
// cache indexes
var cache = _.map(new Array(data.length + 1).join(), function (item, index) {
return index;
});
// get random from cached array
var rand = _.random(0, cache.length);
// remove random index from cache
cache.splice(rand, 1);
console.log(rand, cache)
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
var picked = [];
$("#link").click(function() {
if(data.length == 0) return;
var pick = data.splice(_.random(0,data.length),1);
picked.push(pick);
$("#pick").html(pick);
$("#data").html(data.join(","));
$("#picked").html(picked.join(","));
});
http://jsfiddle.net/Z3vjk/
You could make an array to store the values you've used and check all new random numbers to see if they appear. This would get messy near the end of the array though as the random number generator tries to guess a single number.
If it were me I would just what you alluded to and take the elements out as you use them and place them into a temporary array. Once all elements are used, reassign the temp array to the original variable name.

Categories

Resources