I have an array of monsters. monster is an object for example
{
type: "FIRE",
name: "Sosa",
original: true,
food: ["meet","egg"] // cannot contains 2 identical food
}
what I want is to return the index of the first monster having an X food I have tried this function:
let x = "meet";
let index = -1;
let i = -1;
animals.forEach((animal) => {
i++;
animal.food.forEach((food) => {
if (food === "x") index = i;
});
});
return index;
this is not working for all cases. I am new to programming please some explications and help I will be thankfull
your code is returning the index of the last found item not the first. so it works only when the last found item is at the same time the first found ie only one item is found.
if you really want to use forEach an alternative is to store all found indexes :
var foundIndexes = [];
// your code
if(food === x) foundIndexes.push(i);
//your code
const myIndex = foundIndexes.length == 0 ? -1 : foundIndexes[0] // that means if the array is still empty myIndex = -1 else myIndex = the first element of foundIndexes ie the first found index
return myIndex;
you can also use array.findIndex it does exactly what you are looking for or even array.every to stop the loop once you find the first item
You can use Array#findIndex in conjunction with Array#includes.
let idx = animals.findIndex(a => a.food.includes('x'));
Related
So today I was learning about some ES6 array helpers, and I wanted to change my existing for loops with them, but I can not get same result as i was taking with for loop
function comment(){
let index;
for(let i = 0; i < commentArray.length; i++){
if(commentArray[i]._id == req.params.commentId){
index = commentArray.indexOf(commentArray[i]);
}
}
return index;
}
var com = comment();
It is nodejs and I am trying to get element index from database, and than pull from it, my code works just fine, but I want to change it with array helper, I guess I need find helper, but I can not make it work!
You can replace your for loop with this one-liner which uses Array#findIndex:
let index = commentArray.findIndex(comment => comment._id === req.params.commentId);
When this line executes, it will assign the index of comment, which has _id attribute same as req.params.commentId.
If you want to find the index of the item in the array based on some condition, you can use findIndex function
commentArray.findIndex(comment => comment._id === req.params.commentId)
Also with your current code with for loop, I think you need return the index as soon as it is found and not let the loop iterate till the end.
for(let i = 0; i < commentArray.length; i++){
if(commentArray[i]._id == req.params.commentId){
return commentArray.indexOf(commentArray[i]);
}
}
So I have the following array :
let array = ['9h00','9h30','9h45','10h00','10h15']
Let's say I want to insert '9h15' between '9h00' && '9h30'
How would one do it in a fast & efficient solution ?
EDIT: I have been unclear, the index of the insert would change depending on the array. It won't always be the following position : array[1].
Thanks in advance!
If every item has the same format (\d?\d)h(\d{2}) then we can do the following :
First we need a function to convert the string to an object or something we can work with, I'll go with an object :
function timeStringToObj(str){
var re = "^(\d?\d)h(\d\d)$";
var h = str.replace(re, "$1");
var m = str.replace(re, "$2");
return {
hours: parseInt(h),
minutes: parseInt(m)
};
}
Then we will need to ensure that the array is sorted, for instance "9h15" < "9h16" therefore "9h15"'s index is < "9h16"'s index , (if not use array.sort(/*some sorting function if necessary*/)) and loop through it to find the spot (I'll use a function of course), I'll consider your array as a global variable :
/**
*#param timeObjA an object that is the return value of a call of timeStringToObj
*#param timeObjB an object that is the return value of a call of timeStringToObj
*/
function AgeB(timeObjA, timeObjB){//A greater than or equal to B
return (timeObjA.hours >= timeObjB.hours && timeObjA.minutes >= timeObjB.minutes);
}
/**
*#param a an object that is the return value of a call of timeStringToObj
*#param b an object that is the return value of a call of timeStringToObj
*/
function AleB(a, b){//A less than or equal to B
return (timeObjA.hours <= timeObjB.hours && timeObjA.minutes <= timeObjB.minutes);
}
function putInTimeArray(str){
var val = timeStringToObj(str);
for(let i = 0 ; i < array.length ; i+=1){
var curr = timeStringToObj(array[i]);
//first check : elem >= last
if( AgeB(val, curr) && i===(array.length-1) ){
array.push(str);
return true;
}
//second check : elem <= first
if( AleB(val, curr) && i===0 ){
array.unshift(str);
return true;
}
//last check : first < elem < last
if(i!=0 && i!=(array.length - 1)){
if(AgeB(val, curr)){
array.splice(i+1,0,str);
return true;
}
if(AleB(val, curr){
array.splice(i-1,0,str);//here i-1 is safe since i!=0 (condition)
return true;
}
}//end of last check
}//end of for-loop
}//end of function
If you're having doubts regarding my usage of splice please refer to this : How to insert an item into an array at a specific index?
EDIT
You'll probably need a more sophisticated regex to be more appropriate be this will do the job just fine if you don't go that crazy with those strings
You can push and sort like:
array.push("9h15").sort().reverse(); // ["9h45", "9h30", "9h15", "9h00", "10h15", "10h00"]
Suppose I had a function that is pulling in values from somewhere and storing those values into an array.
function getSport(ply) {
some code here... //function gets values that I need for array later
}
var sports1 = getSport(playerChoice);
var sports2 = getSport(playerChoice);
var sports3 = getSport(playerChoice);
var sports4 = getSport(playerChoice);
var sportsArry = [sports1, sports2, sports3, sports4];
Now I would like to use a for loop to loop the elements, the problem, however, is the first index (index 0) will always be true. I want to skip index 0. How do I do that? Further I want to replace index 0 with something else. Let me show you
for (var i = 0; i<sportsArry.length; i++){
if ( (sports1 == sportsArry[i]) ) {
sports1 = null; //I figured I should null it first?
sports1 = replaceValueFunc(playerChoice2);
}
}
Well you can see the problem I would have. Index 0 is true.
Let me show you what would work, although it requires alot of or operators.
if ( (sports1 == sportsArry[1]) || (sports1 == sportsArry[2]) || (sports1 == sportsArry[3] ) {
...
}
^^ That is one way to skip index 0, what would be another better looking way?
I want to skip index 0. How do I do that? Further I want to replace
index 0 with something else.
Just start the loop from 1 instead of 0
sportsArr[0] = "Something else"; // set the first element to something else
for(var i = 1; i < sportsArr.length; i++){
// do something
}
I am trying to remove an item from an Array using Splice method.
arrayFinalChartData =[{"id":"rootDiv","Project":"My Project","parentid":"origin"},{"1":"2","id":"e21c586d-654f-4308-8636-103e19c4d0bb","parentid":"rootDiv"},{"3":"4","id":"deca843f-9a72-46d8-aa85-f5c3c1a1cd02","parentid":"e21c586d-654f-4308-8636-103e19c4d0bb"},{"5":"6","id":"b8d2598a-2384-407a-e2c2-8ae56c3e47a2","parentid":"deca843f-9a72-46d8-aa85-f5c3c1a1cd02"}];
ajax_delete_id = "e21c586d-654f-4308-8636-103e19c4d0bb,deca843f-9a72-46d8-aa85-f5c3c1a1cd02,b8d2598a-2384-407a-e2c2-8ae56c3e47a2";
$.each(arrayFinalChartData, function (idx, obj) {
var myObj = obj.id;
if (ajax_delete_id.indexOf(myObj) >= 0) {
var vararrayFinalChartDataOne = arrayFinalChartData.splice(idx, 1);
}
});
console.log(arrayFinalChartData);
Please check at : http://jsbin.com/deqix/3/edit
Note : It does not complete the "last leg " of the loop. That means if I have 4 items, then it successfully executes 3 items. Same goes for 6,7...items.
I need to "REMOVE" few items and "PRESERVE THE BALANCE" in an array.
You can use for loop instead of $.each function:
alert('length before delete ' + arrayFinalChartData.length);
for (var i = arrayFinalChartData.length - 1; i >= 0; i--) {
id = arrayFinalChartData[i].id;
if(ajax_delete_id.indexOf(id) > -1){
arrayFinalChartData.splice(i, 1);
}
};
alert('length after delete ' + arrayFinalChartData.length);
Demo.
Complete edit :
After researching a bit, and console.logging a lot, I finally found where the issue is coming from ! It's actually quite simple, but very sneaky !
Theoretical explanation :
You are calling the splice function with the variable "idx", but remember that the splice function remaps / reindexes your array ! So, each time you splice the array, its size decreases by one while you're still inside the $.each function. The splice messes up jQuery indexation of your array, because jQuery doesn't know that you're removing elements from it !
Iterative explanation :
$.each function starts, thinking your array has 4 elements, which is true, but only for a while. First loop, idx = 0, no splice. Second loop, idx = 1, splice, which means that your array has now 3 elements left in it, reindexed from 0 to 2. Third loop, idx = 2, splice, which means your array has now two elements left in it, but $.each continues ! Fourth loop, idx = 3, js crashes, because "arrayFinalChartData[3]" is undefined, since it was moved back each time the array got spliced.
To solve your problem, you need to use a for loop and to start analyzing the array from the end, not from the beginning, hence each time you splice it, your index will decrease as well. And if you want to preserve balance, just push the removed items into an array. Remember that you are analyzing the array from the end, so items pushed into the "removedItems" array will be in reverse order. Just like this :
var removedItems = new Array();
for (var i = arrayFinalChartData.length - 1; i >= 0; i--) {
var myObj = arrayFinalChartData[i].id;
if (ajax_delete_id.indexOf(myObj) >= 0) {
removedItems.push(arrayFinalChartData.splice(i, 1)[0]);
}
}
console.log(arrayFinalChartData);
console.log(removedItems);
And a working demo (inspect the page, observe the console and click "Run") :
http://jsfiddle.net/3mL6C/3/
I will not give credit to myself for this answer, thanks to another similar thread for giving me a hint.
Your problem here is that when the $.each is set up, it's expecting a certain length of object, which you are then changing. You need to loop in a way that respects the dynamic length of the object.
var i = 0;
while (i < arrayFinalChartData.length) {
var myObj = arrayFinalChartData[i].id;
if (ajax_delete_id.indexOf(myObj) >= 0) {
// current item is in the list, so remove it but KEEP THE SAME INDEX
arrayFinalChartData.splice(i, 1);
} else {
// item NOT in list, so MOVE TO NEXT INDEX
i++
}
}
console.log(arrayFinalChartData);
Demo
I am trying to make a JavaScript function that will search an array of strings for a value and return the next string. For example, if an array is built such that an item is followed by its stock code, I want to search for the item and have the stock code written.
var item = (from user input); //some code to get the initial item from user
function findcode(code){
var arr = ["ball", "1f7g", "spoon", "2c8d", "pen", "9c3c"]; //making the array
for (var i=0; i<arr.lenth; i++){ //for loop to look through array
arr.indexOf(item); //search array for whatever the user input was
var code = arr(i+1); //make the variable 'code' whatever comes next
break;
}
}
document.write(code); //write the code, I.e., whatever comes after the item
(I'm sure it's obvious I'm new to JavaScript, and while this is similar to a number of other questions I found, those seemed to have more involved arrays or more complex searches. I can't seem to simplify them for my needs.)
You've almost got it right, but the syntax is arr[x], not arr(x):
index = array.indexOf(value);
if(index >= 0 && index < array.length - 1)
nextItem = array[index + 1]
BTW, using an object instead of an array might be a better option:
data = {"ball":"1f7g", "spoon":"2c8d", "pen":"9c3c"}
and then simply
code = data[name]
Cycled items from array this might be useful
const currentIndex = items.indexOf(currentItem);
const nextIndex = (currentIndex + 1) % items.length;
items[nextIndex];
The first item will be taken from the beginning of the array after the last item
Try this String.prototype function:
String.prototype.cycle = function(arr) {
const i = arr.indexOf(this.toString())
if (i === -1) return undefined
return arr[(i + 1) % arr.length];
};
Here is how you use it:
"a".cycle(["a", "b", "c"]); // "b"
"b".cycle(["a", "b", "c"]); // "c"
"c".cycle(["a", "b", "c"]); // "a"
"item1".cycle(["item1", "item2", "item3"]) // "item2"
If you want to do it the other way round, you can use this Array.prototype function:
Array.prototype.cycle = function(str) {
const i = this.indexOf(str);
if (i === -1) return undefined;
return this[(i + 1) % this.length];
};
Here is how you use it:
["a", "b", "c"].cycle("a"); // "b"
["a", "b", "c"].cycle("b"); // "c"
["a", "b", "c"].cycle("c"); // "a"
["item1", "item2", "item3"].cycle("item1") // "item2"
I think that an object could be probably a better data structure for this kind of task
items = {
ball : "1f7g",
spoon: "2c8d",
pen : "9c3c"
}
console.log(items['ball']); // 1f7g
You may pass array to function as argument and return found value from function:
var item = "spoon"; // from user input
var arr = ["ball", "1f7g", "spoon", "2c8d", "pen", "9c3c"]; //making the array
function findcode(item, arr){
var idx = arr.indexOf(item); //search array for whatever the user input was
if(idx >=0 && idx <= arr.length - 2) { // check index is in array bounds
return arr[i+1]; // return whatever comes next to item
}
return '';
}
document.write(findcode(item, arr)); //write the code, i.e., whatever comes after the item
Answer for 2022
This question came up when I was searching for a modern way to do this. I had been using the technique described in SerzN1's excellent answer without the wraparound (because I don't want that to happen). It winds up being quite a bit of code to make it safe, so I wanted something more modern.
As it turns out, there is a feature that has been available in every major browser since 2016. If someone hasn't updated their browser in six years, that's their loss, right?
ES2015 Array.find()
This function is used for finding a specific element in an array. That's exactly what we want to do here. The only problem is it doesn't maintain state for you, so you can only find a matching element, not the one after (or before, for that matter). To get around that, we use a closure.
Here's the short version:
let trigger = false;
const found = arr.find(element => trigger || (trigger = element === value) && !trigger);
You start with trigger set to false because we need to keep track of when the element is found (if at all). Then we use the Array.find() on the list we should be searching. The single argument to that function is a search function, which we define in-line as a closure so it has access to trigger.
The search function is the tricky part: element => trigger || (trigger = element === query.value) && !trigger. It might be easier to read if I break it apart into a more conventional function just so we can evaluate it. I'll describe what's happening in the comments:
function (element) {
// If trigger is true, that means the previously-evaluated element was the match.
// Therefore, we must be currently evaluating one AFTER it.
// We should match on this one.
if (trigger === true) return true;
// Then we update the value of trigger to the result of comparing the element with the search value
trigger = (element === value)
// Now we `and` it together with its negation in order to make sure
// it always returns false even when the element matches the search value
return trigger && !trigger
}
And there you have it! It only takes two lines of code to get the element after one that matches your query.
Want to see it in action? Here you go:
function showNext() {
const query = document.getElementById('query');
if (query === null) return;
const result = document.getElementById('result');
if (result === null) return;
var arr = ["ball", "1f7g", "spoon", "2c8d", "pen", "9c3c"];
// This is the important part
// Create a boolean flag that will inform the find function when it passes
// the matching element in its search
let trigger = false;
const found = arr.find(element => trigger || (trigger = element === query.value) && !trigger);
// Now `found` is equal to the array element AFTER the one you searched for
// If it is undefined, that means the one you searched for was either the last
// element in the array or it was missing.
result.innerText = `Found ${found ?? 'nothing'}`;
}
<input id="query" />
<input type="submit" value="Display next" onclick="showNext()" />
<div id="result"></div>