Is there a way to combine map and shift in Javascript? - javascript

I'm working with a buffer array that I am periodically checking. When I am mapping through the elements, I would like access the element using the shift method, this way I would get the next element in the array and would also remove it. Is there a way to do this in a map? Thank you!
I currently have a naive solution, which is prone to race conditions.
if (timestep) {
bufferArray.map((mvt) =>{
console.log(mvt)
});
bufferArray = [];
}

As I would like to go through the elements of the array one by one and remove the current element from the array. For this reason a simple and great solution is to use a while loop with the shift method. For example:
let arr = [0,1,2,3,4,5];
while (arr.length)
{
let current = arr.shift()
// do something with current
}

Related

How to take three different words from an array?

I want to create a function taking three random different words from an array
I followed React native filter array not working on string to filter the array. However, the filter is not working.
takeThreeWords=()=>{
for(i=0;i<3;i++){
rand =(max, min=0)=> Math.floor(Math.random()*max-min)
randomWord=()=> this.state.wordsBank[rand(this.state.wordsBank.length)]
let aRandomWord = randomWord()
this.setState(prevState=>({
wordsToUse:[...prevState.wordsToUse, aRandomWord],
wordsBank: prevState.wordsBank.filter(word=>word!== aRandomWord)
}))
The last line is to make sure that no words from wordsBank are taken twice. However, the function works just as if the last line does not exist. wordsToUse take three words, but sometimes they are the same...
Can you please point me out what I am missing ?
You are updating wordsBank via this.setState, but your loop keeps operating on the initial copy of wordsBank, which has not been filtered.
The cleanest fix is to not call this.setState multiple times in a loop.
let wordsBank = this.state.wordsBank;
let extractedWords = [];
while(extractedWords.length<3) {
let i = ~~(Math.random()*wordsBank.length);
extractedWords.push(wordsBank.splice(i, 1)[0]);
}
this.setState(prevState=>({
wordsToUse: [...prevState.wordsToUse, ...extractedWords],
wordsBank
}));

How to get products name insade all arrray?

enter image description hereı want to set custom event with gtm but ı dont know how to get multple producs name . ı can get one of the items name but ı can not get all of them.
document.getElementsByClassName('cartAndCheckout__items')[0].innerText.split('\nStokta var\n3.329,00 TL')[0]
thats the code ı wrote
Seems you just need to iterate the elements that you find via document.getElementsByClassName
let products = []
let elements = document.getElementsByClassName('cartAndCheckout__items')
for(let i=0; i<elements.length; i++){
//products.push(elements[i].innerText)
//based on your comment,if you just want to get the name
let link = elements[i].querySelector('div.mb-2 a')
let title = link.getAttribute("title")
products.push(title)
}
document.getElementsByClassName('cartAndCheckout__items') returns a collection; it looks and mostly works like an array, even though it isn't an Array. You're getting the first item with [0], but you can also for instance loop over all the items:
let products = []
for (const element of document.getElementsByClassName('cartAndCheckout__items')) {
products.push(element.innerText.split('\nStokta var\n3.329,00 TL')[0])
}
Usually if you're building one list from another it's better to use map, but as the collection isn't actually an Array, you have to call it in a roundabout way:
const elements = document.getElementsByClassName('cartAndCheckout__items')
const products = Array.prototype.map.call(elements,
e => e.innerText.split('\nStokta var\n3.329,00 TL')[0])
Please note that ES6 is not supported in GTM, thus you either need to translate the above solution (which is basicly replace "const" and "let" with var :D) or implement the JavaScript natively and push the result to the DataLayer.

Filter an array from another array of elements and return specific positions

I'm finally learning better methods for my JS. I'm trying to find a way to go faster than I do so far :
In my code, I have two arrays :
one with unique keys in first position
one with those keys in first position but not unique. There are multiple entries with a certain value I want to filter.
The thing is I don't want to filter everything that is in the second array. I want to select some positions, like item[1]+item[5]+item[6]. What I do works, but I wonder if there isn't a faster way to do it ?
for (let i=0;i<firstArrayOfUniques.length;i++){
const findRef = secondArrayOfMultiple
.filter(item => item[0]==firstArrayOfUniques[i][0]);
// Afterwards, I redo a map and select only the second element,
//then I join the multiple answers
// Is there a way to do all that in the first filter?
const refSliced = findRef.map(x=>x[1]);
const refJoin = refSliced.join(" - ");
canevasSheet.getRange(1+i,1).setValue(refJoin);
}
The script snippet you quote will spend almost all of its running time calling the Range.setValue() method. It gets called separately for every data row. Use Range.setValues() instead, and call it just once, like this:
function moot(firstArrayOfUniques, secondArrayOfMultiple) {
const result = firstArrayOfUniques.map(uniqueRow =>
secondArrayOfMultiple
.filter(row => row[0] === uniqueRow[0])
.map(row => row[1])
.join(' - '));
canevasSheet.getRange(1, 1, result.length, result[0].length).setValues(result);
}
See Apps Script best practices.

insertBefore function for arrays and/or HTMLCollections?

Does there exist a function in vanilla JavaScript or jQuery that operates similarly to Node.insertBefore(), but for arrays and/or HTMLCollections?
An example could look something like:
var list = document.getElementsByClassName("stuff");
var nodeToMove = list[0];
var otherNode = list[4];
list.insertBefore(nodeToMove, otherNode);
Basically I'm trying to perform insertBefore() without manipulating the actual DOM, as I want the changes to only be applied to the DOM under certain conditions. If those conditions are met, then I would perform insertBefore() on the actual nodes.
To clarify, I'm looking for a function that would insert an element before a target element at a given index in an array, not necessarily at a given index. Examples I've seen using splice() usually insert an element at a given index, which sometimes puts the element before the target element, and sometimes after, depending on where the element to be moved originally was in the array. I'm looking for something that would reliably put the element to be moved before the target element.
HTMLCollection does not have an insertBefore method. jQuery can apply any jQuery methods both to a single element being selected, as well as many.
https://api.jquery.com/insertBefore/
There is no single method to do this in one step, but there doesn't need to be. If you convert the collection to an Array, you can call the Array.prototype.splice() method to achieve the same result.
Here's an example:
let ary = [1,2,3,4,5];
// Swap 2 and 3
// Start at the 3rd item and remove one item (3).
// Store the removed item
let removed = ary.splice(2,1);
// Start at the second item, don't remove anything, insert the removed
// item at that position
ary.splice(1,null,removed[0]);
// Log the result
console.log(ary);
And, with that knowledge, you can create your own more easily callable function:
let ary = [1,2,3,4,5];
function insertBefore(ary, newItem, target){
ary.splice(target,null,newItem);
}
// Insert 999 before the 3rd array item
insertBefore(ary,999,2)
console.log(ary);
You need to get the index you want, then use Array.splice.
Myself I would do something like this :
const myArr = ['Aurore', 'Dimitri', 'Alban', 'Frédéric'];
const insertBeforeThis = 'Alban';
const eltToInsert = 'Laura';
const index = myArr.findIndex(name => name === insertBeforeThis);
myArr.splice(index, 0, eltToInsert);
Please feel free to try it out in your browser's console. Note i used const for my array, as it fixes the type of the variable as an array but allow me to manipulate it.
MDN: Array.prototype.findIndex()
stackoverflow: How to insert an item into an array at a specific index (JavaScript)?
Have a happy coding time!

Possible to .push() to a dynamically named key?

I have an object that I would like to push an indeterminate amount of other objects to, using a loop. To keep it organized, I'd like to dynamically name the keys based on them amount of times the loop runs. I have the following:
let formsJson = {};
let counter = 1;
//savedForms are where the objects that I want to push reside
savedForms.forEach( form => {
formsJson['form'+counter] = JSON.parse(form.firstDataBit_json);
//This is where I'm having trouble
counter = counter + 1;
});
I can push the first bit of data fine, and name the key dynamically as well. But I need to push 2 more objects to this same dynamic key, and that's where I'm having trouble. If I try the obvious and do:
formsJson['form'+counter].push(JSON.parse(form.secondDataBit_JSON));
I don't get any output. Is there a way to accomplish this?
forEach() gives you access to the index already. No need to create the counter variable. Example usage. I would definitely recommend using a simple index, and not using the 'form'+counter key.
In your example, it's not clear to me that the value being assigned in the forEach loop is an array. So it's unclear if you can push to any given element in that. But generally that syntax should
Personally, I would prefer to have a function that outputs the entire value of the element. That would provide better encapsulation, testability, and help enforce default values. Something like:
function createItem(param1) {
let item = [];
item.push(param1.someElement);
if (foo) {
item.push(...);
} else {
item.push(...);
}
return item;
}
formsJson['form'+counter] = createItem( JSON.parse(form) )
So you're making formsJson['form'+counter] a by assigning the JSON parse, not an array as you want. Try this:
formsJson['form'+counter] = [];
formsJson['form'+counter].push(JSON.parse(form.firstDataBit_json));
formsJson['form'+counter].push(JSON.parse(form.secondDataBit_JSON));
Maybe you want to figure out something like this
savedforms.forEach((form, index) =>
formsJson[`form${index + 1}`] = [ JSON.parse(form.secondDataBit_JSON)])
Now you can push on the item
formsJson[`form${index + 1}`].push(JSON.parse(form.secondDataBit_JSON));`
Also here you'll save operation on incrementing it will be automaticly

Categories

Resources