Output several cells from inner loop - javascript

this is my code:
start() {
let columns = ['A'...'Z'];
let fields = {
id: [
'Medlemsnummer',
],
name: [
'Namn',
],
};
let out = {};
let self = this;
columns.forEach(function(column) {
for(let row = 1; row < 101; row++) {
let cell = column + row;
let d_cell = self.worksheet[cell];
let val_cell = (d_cell ? d_cell.v : ' ');
let cell_string = val_cell.toString().toLowerCase();
let cellString_stripped = cell_string.replace(/(?:\r\n|\r|\n)/g, '');
for (var key in fields) {
// skip loop if the property is from prototype
if (!fields.hasOwnProperty(key)) continue;
var obj = fields[key];
for (var prop in obj) {
// skip loop if the property is from prototype
if(!obj.hasOwnProperty(prop)) continue;
obj.forEach(function(term) {
if(cellString_stripped.match(new RegExp(term.toLowerCase() + ".*"))){
//out.push(obj + ': ' + cell);
//out[obj] = {cell};
out[obj] = cell;
}
});
//out[obj]
}
}
}
});
console.log(out);
},
and my problem is that i want several matched cells in out[obj] = // array of matched cells.
how can i do this in javascript?
so my out should look like this:
out = [ medlemsnummer: ['A11','A23','A45'], name: ['B11','B23'] etc... ]
please comment if you need me to explain better.
Kind regards,
Joakim

Looking at your loops, I think you got a little lost in your own structures. out[obj] = cell definitely doesn't seem right; obj is an object, it cannot be used as a key in another object. Here's my take with some notes, hope I interpreted both your code and your question correctly. I'm starting from the loop after all your variables like cell, d_cell, etc. are initialized):
for (let key in fields) {
if (!fields.hasOwnProperty(key)) continue;
let terms = fields[key];
// fields[key] yields us an array, e.g.:
// fields['id'] = [ 'Medlemnummer' ]
// so we can iterate over it directly with for..of.
// Note also: variable names like "obj" make reading your code
// difficult; use meaningful names, e.g. "terms".
for (let term of terms) {
let regex = new RegExp(term.toLowerCase() + ".*");
// Note: RegEx.test() is more efficient than String.match()
// if all you need is a yes/no answer.
if (!regex.test(cellString_stripped)) continue;
// Here's the part you actually needed help with:
if (!out[term]) {
out[term] = [];
}
out[term].push(cell);
}
}
Addendum: In the code I'm sticking with your solution to use RegExp to test the strings. However, if all you need to check is whether the string starts with the given substring, then it's much shorter and more efficient to use String.startsWith():
for (let term of terms) {
if (!cellString_stripped.startsWith(term.toLowerCase())) continue;
// Here's the part you actually needed help with:
if (!out[term]) {
out[term] = [];
}
out[term].push(cell);
}

Related

Why is this for loop reverting to 0 and never getting to the end of the size of this array

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)
}

Loop, get unique values and update

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;
}

Hashmap not adding new Keys and Values - Javascript

I'm new to this, so go easy please lol.
I've got a hashmap, and I'm attempting to dynamically add new keys and values. I'm doing this in a for loop, but for some reason, the only key and value that gets added to the hashmap is the last one found by the for loop.
Here's my code:
//HASHMAP BEGINNING HERE;
var newKey;
var newValue;
var MQHash = {};
for (var c = 0; c < lines.length; c++) {
if (lines[c].match(/\.\w+\s\{|\.\-\w+\s\{|\.\w+\-\w+\s\{/)) {
console.log("It works!");
console.log(lines[c].match(/\.\w+\s\{|\.\-\w+\s\{|\.\w+\-\w+\s\{/));
//Saving the match as newKey
newKey = lines[c].match(/\.\w+\s\{|\.\-\w+\s\{|\.\w+\-\w+\s\{/);
console.log("NEWKEY", newKey);
}
if (lines[c].match(/\{(.*)(.*)\}/)) {
console.log(lines[c].match(/\{(.*)(.*)\}/));
//Saving the match as newValue
newValue = lines[c].match(/\{(.*)(.*)\}/)[1];
//Pushing them both into the hashmap
//MQHash.push(newKey, newValue);
//ALSO TRIED IT THIS WAY
MQHash[newKey] = newValue;
}
}
This is what the output of the final hashmap looks like:
"Final Version" Object { .bg-color {: " width: 400px; " }
And I know that there are supposed to be more values within that key.
Any suggestions? Thanks in advance!

Javascript : Select Element in URL with multiple instance of the same element

i need to retrieve a value from an URL in JS, my problem is in this url, the element is repeated at least twice with different value. What i need is the last one.
Example :
http://randomsite.com/index.php?element1=random1&element2=random2&element1=random3
and what i want is "random3" and NOT "random1"
I've tried url.match(/.(\&|\?)element1=(.?)\&/)[2];
But it always gives me the first one :(
I don't have the possibility to change how the url is written as this is for a browser extension.
var ws = "http://randomsite.com/index.php?element1=random1&element2=random2&element1=random3",
input = ws.split("?")[1].split("&"),
dataset = {},
val_to_find = "element1";
for ( var item in input){
var d = input[item].split("=");
if (!dataset[d[0]]){ dataset[d[0]] = new Array(); dataset[d[0]].push(d[1]); }
else{
dataset[d[0]].push(d[1]);
}
}
console.log("item: ", dataset[val_to_find][dataset[val_to_find].length -1]);
return dataset[val_to_find][dataset[val_to_find].length -1];
http://jsfiddle.net/wMuHW/
Take the minimum value (other than -1) from urlString.lastIndexOf("&element1=") and urlString.lastIndexOf("?element1="), then use urlString.substring.
Or alternately, split the string up:
var parts = urlString.split(/[?&]/);
...which will give you:
[
"http://randomsite.com/index.php",
"element1=random1",
"element2=random2",
"element1=random3"
]
...then start looping from the end of the array finding the first entry that starts with element= and grabbing the bit after the = (again with substring).
You could;
for (var result, match, re = /[&?]element1=(.+?)(\&|$)/g; match = re.exec(url);) {
result = match[1];
}
alert(result);
Id try keeping a nested array of duplicate elements
function parseQueryString() {
var elements = {},
query = window.location.search.substring(1),
vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('='),
key = decodeURIComponent(pair[0]),
value = decodeURIComponent(pair[1]);
if (elements.hasOwnProperty(key)) {
elements[key].push(value);
}
else {
elements[key] = [value];
}
}
}
Used on: www.example.com?element1=hello&element2=test&element1=more
Would give you the object:
{
element1: [
"hello",
"more"
],
element2:[
"test"
]
}

reading all the submatches in regexp multiple matches

today i'm trying to parse a 'ps aux' output (issued from a node.js server)
so i made an happy regex to parse the values, and i wanted to put all those fancy informations into a simple JSON object :-)
problem is, the regex i've made has 3 match groups, doing multiple matches... and i don't even know if it's possible to have it all the matches returned.
var spawn = require("child_process").spawn;
function exec(http_req, http_resp){
var re_ps = /(?:([\d\.\w\-\?\/\+]+)\s+){8}(?:((?:\d+\:\d+)|(?:\w+\d+))\s+){2}([^\n]+)/g,
result_re_ps,
array_re_ps = [];
//[USER, PID, %CPU, %MEM, VSZ, RSS, TTY, STAT], dates[START, TIME], COMMAND
var ps_process = spawn("ps", ["aux"]);
ps_process.stdout.on("data", function(data){
var split_data = data.toString().split('\n');
for (var i=1; i < 2; i++){
while ((result_re_ps = re_ps.exec(split_data[i])) != null){
console.log("--- while iteration ---");
console.dir(result_re_ps);
//console.dir(result_re_ps);
}
}
//http_resp.write(data);
});
ps_process.on("exit", function (code) {
if (code !== 0) {
console.log("ps_process exited with code " + code);
}
http_resp.end();
});
}
exports.exec = exec;
the "--- while iteration ---" it's just one per each line, instead, it should be multiples!
I will link a fancy screenshot to let you visually understand what kind of data i'm expecting
As you can see the above are 3 groups of data, each one with multiple occurrences
Any help? :p
EDITED TO CLARIFY:
This is the result of a line like:
root 5213 0.0 2.1 8688 2760 ? Ss 11:33 0:01 sshd: root#pts/0
As you can see, the resulting array is 1-dimensional, instead for the results to be contained entirely it HAS to be at least 2-dimensional
UPDATE:
For now i've solved the problem changin my code like this:
var spawn = require("child_process").spawn;
function exec(http_req, http_resp){
var array_re_ps = [];
var re_ps1 = /(?:([\d\.\w\-\?\/\+]+)\s+)/g,
re_ps2 = /(?:((?:\d+\:\d+)|(?:\w+\d+))\s+)/g,
re_ps3 = /([^\n]+)/g;
//[USER, PID, %CPU, %MEM, VSZ, RSS, TTY, STAT], dates[START, TIME], COMMAND
var ps_process = spawn("ps", ["aux"]);
ps_process.stdout.on("data", function(data){
var split_data = data.toString().split('\n');
for (var i=20; i < 21; i++){
array_re_ps[0] = [], array_re_ps[1] = [];
for (var j=0; j<8; j++){
array_re_ps[0].push(re_ps1.exec(split_data[i])[1]);
}
re_ps2.lastIndex = re_ps1.lastIndex;
for (var j=0; j<2; j++){
array_re_ps[1].push(re_ps2.exec(split_data[i])[1])
}
re_ps3.lastIndex = re_ps2.lastIndex;
array_re_ps[2] = re_ps3.exec(split_data[i])[1];
console.dir(array_re_ps);
}
});
ps_process.on("exit", function (code) {
if (code !== 0) {
console.log("ps_process exited with code " + code);
}
http_resp.end();
});
}
exports.exec = exec;
Basically i split my long regexp, in 3 smaller ones, and i do cycle through their results.
If you try the code i formatted the resulting array exactly as i wanted, but i still think that it's a side-solution.
Since Regular Expressions lets you "multiple parse group multiple times", it is possible to have that functionality in javascript?
Take a look at the return values of the exec function.
It returns the index where it first matched, the original string and the capture groups in the elements [0]...[n].
All this is available in your output, you just have to iterate through the single elements of the array.

Categories

Resources