I'm having trouble finding the right way to find if an item from a for loop is in an array. Let's say I have a for loop that is iterating through some results. If they are in an array:
ctids = [];
continue to the next step in the for loop, but if not, push them to the array and do something else. What is the correct syntax for this?
for (var i=0;i<results.features.length;i++){
ACS_BG = results.features[i].attributes.BLKGRPCE;
ACS_ST = results.features[i].attributes.STATEFP;
ACS_CNTY = results.features[i].attributes.COUNTYFP;
ACS_TRCT = results.features[i].attributes.TRACTCE;
if ACS_TRCT exists in ctids { //This is where I am having trouble.
continue; //skip the rest of the if statement
} else {
ctids.push(ACS_TRCT);
// do something else;
};
};
Can you please try this code
var ctids = []
for (var i=0;i<results.features.length;i++){
ACS_BG = results.features[i].attributes.BLKGRPCE;
ACS_ST = results.features[i].attributes.STATEFP;
ACS_CNTY = results.features[i].attributes.COUNTYFP;
ACS_TRCT = results.features[i].attributes.TRACTCE;
if(!ctids.includes(ACS_TRCT))
{
ctids.push(ACS_TRCT);
}
};
You can use includes to check if the elment exist in array and if not push the element into it.
if (ctids.includes(ACS_TRCT)){
continue;
}else{
ctids.push(ACS_TRCT)
}
I'd do:
for (var i = 0; i < results.features.length; i++) {
const ACS_BG = results.features[i].attributes.BLKGRPCE;
const ACS_ST = results.features[i].attributes.STATEFP;
const ACS_CNTY = results.features[i].attributes.COUNTYFP;
const ACS_TRCT = results.features[i].attributes.TRACTCE;
// push ACS_TRCT, ACS_ST, ACS_TRCT, ACS_CNTY to resulting
// array ctids if they don't present using `.includes` method.
if (!ctids.includes(ACS_TRCT)) ctids.push(ACS_TRCT);
if (!ctids.includes(ACS_ST)) ctids.push(ACS_ST);
if (!ctids.includes(ACS_CNTY)) ctids.push(ACS_CNTY);
if (!ctids.includes(ACS_TRCT)) ctids.push(ACS_TRCT);
}
You can use .find to check if the item is already present in the array ( will only work for primitive types )
var found = ctids.find(function(value) {
return ACS_TRCT === value;
});
if(!found) {
ctids.push(ACS_TRCT);
}
Related
This problem refers to the hackerank anagram question here:
For some reason, this for loop never completes. It gets to 3 (-2 from the length of the array it is iterating over) and then goes back to 0 and I can't tell why.
const dictionary = ['hack', 'a' , 'rank' , 'khac','ackh']
const query = ['a','nark','bs','hack','stair']
console.log(stringAnagram(dictionary, query))
function stringAnagram(dictionary, query){
let sortedDictionary=[];
let sortedQuery = [];
let alphabetisedWord;
let sortedWord;
let anagramsCount = [];
// sort them
for(let i = 0; i<dictionary.length-1; i++){
sortedWord= dictionary[i];
if(dictionary[i].length > 1){
sortedWord= sortedWord.split('');
console.log('sortedWord: ',sortedWord)
sortedWord= sortedWord.sort();
console.log('sortedWord: ',sortedWord)
sortedWord= sortedWord.join('');
console.log('sortedWord: ',sortedWord)
sortedDictionary[i] = sortedWord;
} else {
sortedDictionary[i] = sortedWord;
}
console.log(i, dictionary.length)
}
for(let i = 0; i<query.length-1; i++){
alphabetisedWord = query[i];
if(query[i].length > 1){
alphabetisedWord = alphabetisedWord.split('');
console.log('alpha : ', alphabetisedWord)
alphabetisedWord = alphabetisedWord.sort();
alphabetisedWord = alphabetisedWord.join('');
}
var regex = new RegExp("/" + alphabetisedWord + "/", "g");
console.log(stringAnagram(dictionary, query))
anagramsCount[i] = sortedDictionary.toString().match(regex).length
sortedQuery[i] = alphabetisedWord;
}
return anagramsCount;
}
Can anyone tell what's causing this? I have tried logging all the indexes and words but I did a similar question earlier with a similar method of answering - only this time, the endless loop has appeared and I have never seen this before.
If a simple problem seems impossible, you're doing it a wrong way... eek talking to myself too
const dictionary = ['hack', 'a' , 'rank' , 'khac','ackh']
const query = ['a','nark','bs','hack','stair']
console.log(stringAnagram(dictionary, query))
function stringAnagram(dd,qq){
var j=(x)=>{return JSON.parse(JSON.stringify(x))} //function to ensure an object isn't passed as pointer JUST IN CASE and to that dude critisizing this part, stringifying an already correctly evaluated obj works(therefore parsing that would be parsing a correctly stringified obj)
var d=j(dd); var q=j(qq)
//make words in both query and dictionary now have their words in only 1 format(so that indexOf would work like a charm)
d=d.map(a=>{return a.split``.sort().join``})
q=q.map(a=>{return a.split``.sort().join``})
//now onto indexOf logic(returns the FIRST find of what ur looking for in an array)
var arr=[]
q.forEach(a=>{
var i=0
while(d.indexOf(a)!=-1){
var y=d.indexOf(a)
i++;d.splice(y,1)
}
arr.push(i)
})
return(arr)
}
This is my function for adding all elements from array one to array two:
function addAll() {
var mList = JSON.parse(JSON.stringify(vm.feeds))
for (var i = 0; i < mList.length; i++) {
mList[i].is_selected = false;
vm.rationList.push(mList[i]);
}
vm.feeds = [];
vm.rationListSafe = vm.rationList;
if(vm.feeds.length == 0){
vm.currentPageMaster++;
vm.isPage = true;
vm.disableScroll = true;
getFeedsByTeam(vm.selectedTeam);
}
}
From array vm.feeds i add elements to array vm.rationList. Is there any way I can prevent adding same elements twice?
Consider Set constructor. It generates an array of unique values
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
I have a following data array :
[{"name":"joseph","time":"0","status":"Idle"}] //there are multiple objects inside the array
This array of objects is generated every second by a node js service. I want to compare the newly created array with the previously created array to check for the change of the status.
eg
case 1
newly created
[{"name":"joseph","time":"0","status":"Idle"}]
previously created
[{"name":"joseph","time":"0","status":"Idle"}]
comparing the status of new and previous object : No change in status
case 2
newly created
[{"name":"joseph","time":"0","status":"Calling"}]
previously created
[{"name":"joseph","time":"0","status":"Idle"}]
comparing the status of new and previous object : status has changed
I hope you get the point.
If the status has changed then assign the current time to the time key;
I'm not able to figure out how to save the previous array and compare it with the newly created array.
What I have done so far:
newarray = [{"name":"joseph","time":"0","status":"Calling"}];
previousarray = newarray;
for(i=0;i<=newarray.length;i++){
for(j=0;j<previousarray.length;j++){
if(previousarray[j].status != newarray[i].status){
newarray[i].time = moment().format('H:mm:ss');
}
}
}
but this doesn't work. I get error like :
TypeError: Cannot read property 'status' of undefined
How do I do it?
First your previousArray is a reference to the newArray using =
Use the spread operator syntax instead:
const previousArray = [...newArray];
Then in the first loop you have <= instead of <
const newarray = [{"name":"joseph","time":"0","status":"Calling"}];
const previousarray = [...newarray];
for(let i = 0; i < newarray.length; i++) {
for(let j = 0; j < previousarray.length; j++) {
if(previousarray[j].status != newarray[i].status) {
newarray[i].time = moment().format('H:mm:ss');
}
}
}
can do in the below possible way. assuming newly_created & previously_created
newly_created = [{"name":"joseph","time":"0","status":"Calling"}, {"name":"joseph - 2","time":"0","status":"Idle"}, {"name":"joseph - 3","time":"0","status":"Calling"}];
previously_created = [{"name":"joseph","time":"0","status":"Idle"}, {"name":"joseph - 2","time":"0","status":"Calling"}, {"name":"joseph - 3","time":"0","status":"Calling"}];
newly_created.forEach(function(newArrObj, index){
if(newArrObj.status !== previously_created[index].status){
// newArrObj.time = moment().format('H:mm:ss');
newArrObj.time = new Date().toTimeString().split(' ')[0];
}
});
console.log('New Array : ', newly_created);
I think you want to do something like this:
newarray = {"name":"joseph","time":"0","status":"Calling"};
previousarray = newarray;
if(previousarray['status'] !== newarray['status']){
newarray['time'] = "date-time";
}
Please, can you check my code where is the error? It should loop trough 1 array to choose each string and then loop through second array and check, if the value from second string contains value of first string.
for (var i = 0; i < oldLines.length; i++){
var subStringEach = oldLines[i];
var subStringEachNoDash = subStringEach.replace(/[^a-z0-9]/g,'');
// read New URLs and line by line save them as an object
var newLines = $('#newUrl').val().split(/\n/);
var newUrlResult = [];
for (var j = 0; j < newLines.length; j++){
var newUrlString = newLines[j];
var newUrlStringNoDash = newUrlString.replace(/[^a-z0-9]/g,'');
var isThere = newUrlStringNoDash.search(subStringEachNoDash);
if (isThere !== -1 ) {
newUrlResult[i] = newLines[j];
}
else {
newUrlResult[i] = "";
}
}
stockData.push({OldURL:oldLines[i],SearchSubstring:subStringEach,NewURL:newUrlResult[i]});
}
Now it finds only part of the results.. I place to first array:
anica-apartment
casa-calamari-real
ostrovni-apartman
and to the second array:
http://tempweb3.datastack.cz/be-property/anica-apartment/
http://tempweb3.datastack.cz/be-property/ostrovni-apartman/
http://tempweb3.datastack.cz/be-property/st-michael-apartment/
http://tempweb3.datastack.cz/be-property/casa-calamari-real/
and it will only find and return casa-calamari-real, http://tempweb3.datastack.cz/be-property/casa-calamari-real/ and the others returns empty..
Any ideas please?
Here is the full code on Codepen: https://codepen.io/vlastapolach/pen/VWRRXX
Once you find a match you should exit the inner loop, otherwise the next iteration of that loop will clear again what you had matched.
Secondly, you should use push instead of accessing an index, as you don't know how many results you will have. And as a consequence you will need to relate the find string with it (because i will not be necessary the same in both arrays)
So replace:
if (isThere !== -1 ) {
newUrlResult[i] = newLines[j];
}
else {
newUrlResult[i] = "";
}
with this:
if (isThere !== -1 ) {
newUrlResult.push({
searchSubstring: subStringEach,
newURL: newUrlString
});
break; // exit loop
}
At the end, just output newUrlResult.
NB: If you want to leave the possibility that a search string matches with more than one URL, then you don't need the break. The push will then still prevent you from overwriting a previous result.
I see that you solved already) But maybe you will like this code too)
newUrlResult variable could be a string I guess, because loop breaks when one value is found. If no values where found there will be just empty string. And I'm not sure you need to call newLines = $('#newUrl').val().split(/\n/) on every iteration.
var stockData = [];
oldLines.map(function(oldLine){
var cleanOldLine = oldLine.replace(/[^a-z0-9]/g,''),
newLines = $('#newUrl').val().split(/\n/),
newUrlResult = '';
for (var j = 0; j < newLines.length; j++){
var newLine = newLines[j],
cleanNewLine = newLine.replace(/[^a-z0-9]/g,''),
ifExists = cleanNewLine.search(cleanOldLine);
if (ifExists !== -1) {
newUrlResult = newLine;
break;
}
}
stockData.push({OldURL:oldLine, SearchSubstring:cleanOldLine, NewURL:newUrlResult});
});
I am doing the below to get certain nodes from a treeview followed by getting text from those nodes, filtering text to remove unique and then appending custom image to the duplicate nodes.
For this I am having to loop 4 times. Is there is a simpler way of doing this? I am worried about it's performance for large amount of data.
//Append duplicate item nodes with custom icon
function addRemoveForDuplicateItems() {
var treeView = $('#MyTree').data('t-TreeView li.t-item');
var myNodes = $("span.my-node", treeView);
var myNames = [];
$(myNodes).each(function () {
myNames.push($(this).text());
});
var duplicateItems = getDuplicateItems(myNames);
$(myNodes).each(function () {
if (duplicateItems.indexOf($(this).text()) > -1) {
$(this).parent().append(("<span class='remove'></span>"));
}
});
}
//Get all duplicate items removing unique ones
//Input [1,2,3,3,2,2,4,5,6,7,7,7,7] output [2,3,3,2,2,7,7,7,7]
function getDuplicateItems(myNames) {
var duplicateItems = [], itemOccurance = {};
for (var i = 0; i < myNames.length; i++) {
var dept = myNames[i];
itemOccurance[dept] = itemOccurance[dept] >= 1 ? itemOccurance[dept] + 1 : 1;
}
for (var item in itemOccurance) {
if (itemOccurance[item] > 1)
duplicateItems.push(item);
}
return duplicateItems;
}
If I understand correctly, the whole point here is simply to mark duplicates, right? You ought to be able to do this in two simpler passes:
var seen = {};
var SEEN_ONCE = 1;
var SEEN_DUPE = 2;
// First pass, build object
myNodes.each(function () {
var name = $(this).text();
var seen = seen[name];
seen[name] = seen ? SEEN_DUPE : SEEN_ONCE;
});
// Second pass, append node
myNodes.each(function () {
var name = $(this).text();
if (seen[name] === SEEN_DUPE) {
$(this).parent().append("<span class='remove'></span>");
}
});
If you're actually concerned about performance, note that iterating over DOM elements is much more of a performance concern than iterating over an in-memory array. The $(myNodes).each(...) calls are likely significantly more expensive than iteration over a comparable array of the same length. You can gain some efficiencies from this, by running the second pass over an array and only accessing DOM nodes as necessary:
var names = [];
var seen = {};
var SEEN_ONCE = 1;
var SEEN_DUPE = 2;
// First pass, build object
myNodes.each(function () {
var name = $(this).text();
var seen = seen[name];
names.push(name);
seen[name] = seen ? SEEN_DUPE : SEEN_ONCE;
});
// Second pass, append node only for dupes
names.forEach(function(name, index) {
if (seen[name] === SEEN_DUPE) {
myNodes.eq(index).parent()
.append("<span class='remove'></span>");
}
});
The approach of this code is to go through the list, using the property name to indicate whether the value is in the array. After execution, itemOccurance will have a list of all the names, no duplicates.
var i, dept, itemOccurance = {};
for (i = 0; i < myNames.length; i++) {
dept = myNames[i];
if (typeof itemOccurance[dept] == undefined) {
itemOccurance[dept] = true;
}
}
If you must keep getDuplicateItems() as a separate, generic function, then the first loop (from myNodes to myNames) and last loop (iterate myNodes again to add the span) would be unavoidable. But I am curious. According to your code, duplicateItems can just be a set! This would help simplify the 2 loops inside getDuplicateItems(). #user2182349's answer just needs one modification: add a return, e.g. return Object.keys(itemOccurance).
If you're only concerned with ascertaining duplication and not particularly concerned about the exact number of occurrences then you could consider refactoring your getDuplicateItems() function like so:
function getDuplicateItems(myNames) {
var duplicateItems = [], clonedArray = myNames.concat(), i, dept;
for(i=0;i<clonedArray.length;i+=1){
dept = clonedArray[i];
if(clonedArray.indexOf(dept) !== clonedArray.lastIndexOf(dept)){
if(duplicateItems.indexOf(dept) === -1){
duplicateItems.push(dept);
}
/* Remove duplicate found by lastIndexOf, since we've already established that it's a duplicate */
clonedArray.splice(clonedArray.lastIndexOf(dept), 1);
}
}
return duplicateItems;
}