EDIT
Thank you guys, and i apologize for not being more specific in my question.
This code was written to check if a characters in the second string is in the first string. If so, it'll return true, otherwise a false.
So my code works, I know that much, but I am positive there's gotta be a better way to implement this.
Keep in mind this is a coding challenge from Freecodecamp's Javascript tree.
Here's my code:
function mutation(arr) {
var stringOne = arr[0].toLowerCase();
var stringTwo = arr[1].toLowerCase().split("");
var i = 0;
var truthyFalsy = true;
while (i < arr[1].length && truthyFalsy) {
truthyFalsy = stringOne.indexOf(stringTwo[i]) > -1;
i++
}
console.log(truthyFalsy);
}
mutation(["hello", "hey"]);
//mutation(["hello", "yep"]);
THere's gotta be a better way to do this. I recently learned about the map function, but not sure how to use that to implement this, and also just recently learned of an Array.prototype.every() function, which I am going to read tonight.
Suggestions? Thoughts?
the question is very vague. however what i understood from the code is that you need to check for string match between two strings.
Since you know its two strings, i'd just pass them as two parameters. additionally i'd change the while into a for statement and add a break/continue to avoid using variable get and set.
Notice that in the worst case its almost the same, but in the best case its half computation time.
mutation bestCase 14.84499999999997
mutation worstCase 7.694999999999993
bestCase: 5.595000000000027
worstCase: 7.199999999999989
// your function (to check performance difference)
function mutation(arr) {
var stringOne = arr[0].toLowerCase();
var stringTwo = arr[1].toLowerCase().split("");
var i = 0;
var truthyFalsy = true;
while (i < arr[1].length && truthyFalsy) {
truthyFalsy = stringOne.indexOf(stringTwo[i]) > -1;
i++
}
return truthyFalsy;
}
function hasMatch(base, check) {
var strOne = base.toLowerCase();
var strTwo = check.toLowerCase().split("");
var truthyFalsy = false;
// define both variables (i and l) before the loop condition in order to avoid getting the length property of the string multiple times.
for (var i = 0, l = strTwo.length; i < l; i++) {
var hasChar = strOne.indexOf(strTwo[i]) > -1;
if (hasChar) {
//if has Char, set true and break;
truthyFalsy = true;
break;
}
}
return truthyFalsy;
}
var baseCase = "hello";
var bestCaseStr = "hey";
var worstCaseStr = "yap";
//bestCase find match in first iteration
var bestCase = hasMatch("hello", bestCaseStr);
console.log(bestCase);
//worstCase loop over all of them.
var worstCase = hasMatch("hello", worstCaseStr);
console.log(worstCase);
// on your function
console.log('mutation bestCase', checkPerf(mutation, [baseCase, bestCaseStr]));
console.log('mutation worstCase', checkPerf(mutation, [baseCase, worstCaseStr]));
// simple performance check
console.log('bestCase:', checkPerf(hasMatch, baseCase, bestCaseStr));
console.log('worstCase:', checkPerf(hasMatch, baseCase, worstCaseStr));
function checkPerf(fn) {
var t1 = performance.now();
for (var i = 0; i < 10000; i++) {
fn(arguments[1], arguments[2]);
}
var t2 = performance.now();
return t2 - t1;
}
1
11
12
1121
122111
112213
122211
....
I was trying to solve this problem. It goes like this.
I need to check the former line and write: the number and how many time it was repeated.
ex. 1 -> 1(number)1(time)
var antsArr = [[1]];
var n = 10;
for (var row = 1; row < n; row++) {
var lastCheckedNumber = 0;
var count = 1;
antsArr[row] = [];
for (var col = 0; col < antsArr[row-1].length; col++) {
if (lastCheckedNumber == 0) {
lastCheckedNumber = 1;
antsArr[row].push(lastCheckedNumber);
} else {
if (antsArr[row-1][col] == lastCheckedNumber) {
count++;
} else {
lastCheckedNumber = antsArr[row-1][col];
}
}
}
antsArr[row].push(count);
antsArr[row].push(lastCheckedNumber);
}
for (var i = 0; i < antsArr.length; i++) {
console.log(antsArr[i]);
}
I have been on this since 2 days ago.
It it so hard to solve by myself. I know it is really basic code to you guys.
But still if someone who has a really warm heart help me out, I will be so happy! :>
Try this:
JSFiddle Sample
function lookAndSay(seq){
var prev = seq[0];
var freq = 0;
var output = [];
seq.forEach(function(s){
if (s==prev){
freq++;
}
else{
output.push(prev);
output.push(freq);
prev = s;
freq = 1;
}
});
output.push(prev);
output.push(freq);
console.log(output);
return output;
}
// Sample: try on the first 11 sequences
var seq = [1];
for (var n=0; n<11; n++){
seq = lookAndSay(seq);
}
Quick explanation
The input sequence is a simple array containing all numbers in the sequence. The function iterates through the element in the sequence, count the frequency of the current occurring number. When it encounters a new number, it pushes the previously occurring number along with the frequency to the output.
Keep the iteration goes until it reaches the end, make sure the last occurring number and the frequency are added to the output and that's it.
I am not sure if this is right,as i didnt know about this sequence before.Please check and let me know if it works.
var hh=0;
function ls(j,j1)
{
var l1=j.length;
var fer=j.split('');
var str='';
var counter=1;
for(var t=0;t<fer.length;t++)
{
if(fer[t]==fer[t+1])
{
counter++;
}
else
{
str=str+""+""+fer[t]+counter;
counter=1;
}
}
console.log(str);
while(hh<5) //REPLACE THE NUMBER HERE TO CHANGE NUMBER OF COUNTS!
{
hh++;
//console.log(hh);
ls(str);
}
}
ls("1");
You can check out the working solution for in this fiddle here
You can solve this by splitting your logic into different modules.
So primarily you have 2 tasks -
For a give sequence of numbers(say [1,1,2]), you need to find the frequency distribution - something like - [1,2,2,1] which is the main logic.
Keep generating new distribution lists until a given number(say n).
So split them into 2 different functions and test them independently.
For task 1, code would look something like this -
/*
This takes an input [1,1,2] and return is freq - [1,2,2,1]
*/
function find_num_freq(arr){
var freq_list = [];
var val = arr[0];
var freq = 1;
for(i=1; i<arr.length; i++){
var curr_val = arr[i];
if(curr_val === val){
freq += 1;
}else{
//Add the values to the freq_list
freq_list.push([val, freq]);
val = curr_val;
freq = 1;
}
}
freq_list.push([val, freq]);
return freq_list;
}
For task 2, it keeps calling the above function for each line of results.
It's code would look something like this -
function look_n_say(n){
//Starting number
var seed = 1;
var antsArr = [[seed]];
for(var i = 0; i < n; i++){
var content = antsArr[i];
var freq_list = find_num_freq(content);
//freq_list give an array of [[ele, freq],[ele,freq]...]
//Flatten so that it's of the form - [ele,freq,ele,freq]
var freq_list_flat = flatten_list(freq_list);
antsArr.push(freq_list_flat);
}
return antsArr;
}
/**
This is used for flattening a list.
Eg - [[1],[1,1],[1,2]] => [1,1,1,1,2]
basically removes only first level nesting
**/
function flatten_list(li){
var flat_li = [];
li.forEach(
function(val){
for(ind in val){
flat_li.push(val[ind]);
}
}
);
return flat_li;
}
The output of this for the first 10 n values -
OUTPUT
n = 1:
[[1],[1,1]]
n = 2:
[[1],[1,1],[1,2]]
n = 3:
[[1],[1,1],[1,2],[1,1,2,1]]
n = 4:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1]]
n = 5:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3]]
n = 6:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1]]
n = 7:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1],[1,1,2,3,1,2,3,1,1,1]]
n = 8:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1],[1,1,2,3,1,2,3,1,1,1],[1,2,2,1,3,1,1,1,2,1,3,1,1,3]]
n = 9:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1],[1,1,2,3,1,2,3,1,1,1],[1,2,2,1,3,1,1,1,2,1,3,1,1,3],[1,1,2,2,1,1,3,1,1,3,2,1,1,1,3,1,1,2,3,1]]
I'm am starting in javascript. I'm trying to do a little program that make a statistic upon the number of answer found in a text document.
The situation is this: each question has one id, e.g 8000001 and W if answer is good or R if answer is not good, e.g for an user answer is 8000001W. I have many user so many question of the same id. I want to get number of good answers per questions. E.g id: 800001 have W: 24 and "R": 5.
I have split the answer into id for 8000001 and ans for W or R. I wanted to create an associative table to get question[id]=["W": 0, "R": 0]. But I'm blocking on this. I've tried this code:
var tab = [];
tab[0] = [];
tab[0] = ['8000001W', '8000002W', '8000003W', '8000004R', '8000005W', '8000006R'];
tab[1] = [];
tab[1] = ['8000001R', '8000002W', '8000003R', '8000004W', '8000005R', '8000006W'];
var question = [];
var id;
for (var i=0;i<tab.length;i++) {
document.write("<dl><dt>tableau n° "+i+"<\/dt>");
for (var propriete in tab[i]) {
id = tab[i][propriete].slice(0,7);
var ans = tab[i][propriete].slice(7,8);
question[id] = [];
if(question[id]){
incrementResp.call(rep, ans);
}else{
var rep = initResp(ans);
question[id] = rep;
}
}
document.write("<\/dl>");
}
function incrementResp(type){
this.this++;
}
function initResp(t){
rep = [];
rep.W = (t=='W'?1:0);
rep.R = (t=='R'?1:0);
}
Based on what your want finally, the 'question' should be used as an object literal, defined as question = {} (similar to association array), what you defined here is an array literal. You can check this for more information about different types of literals in JavaScript:
https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#Literals
In terms of your code, you can simple do like this:
if (question[id]) {
question[id][ans] += 1;
}
else {
var rep = initResp(ans);
question[id] = rep;
}
Also your 'initResp' function better to return an object literal 'rep', not as an array literal:
function initResp(t){
var rep = {};
rep.W = (t=='W'?1:0);
rep.R = (t=='R'?1:0);
return rep;
}
For an "associative array" in JavaScript, use a regular object. In the code below, "results" is one of these objects. It has two keys, "W" and "R" that point to numbers starting at 0. Just iterate through your answer arrays and continuously increment the correct key.
There are two ways to access a key in an object: 1) using brackets, 2) using "dot" notation. In the loop I use brackets because 'key' is a variable--it will resolve to "W" or "R" and therefore access the "W" or "R" key in that object. In the final two lines I use dot notation because "W" and "R" are literally the keys I want to access. It would also work if I did this instead: results['W']++ and results['R']++.
var tab = [];
tab[0] = ['8000001W', '8000002W', '8000003W', '8000004R', '8000005W', '8000006R'];
tab[1] = ['8000001R', '8000002W', '8000003R', '8000004W', '8000005R', '8000006W'];
var results = {
W: 0,
R: 0
};
// go through each tab
for (var tabIdx = 0; tabIdx < tab.length; tabIdx++) {
// go through each answer and apppend to an object that keeps the results
for (var i = 0; i < tab[tabIdx].length; i++) {
var answer = tab[tabIdx][i];
// the last character in the string is the "key", (W or R)
var key = answer.slice(-1);
// append to the results object
results[key]++;
}
}
console.log(results);
console.log(results.W); // 7
console.log(results.R); // 5
Open up your development console (on Chrome it's F12) to see the output.
This is how i resolved my problem for associative array.
var tab = [];
tab[0] = ['8000001W', '8000002W', '8000003W', '8000004R', '8000005W', '8000006R'];
tab[1] = ['8000001R', '8000002W', '8000003R', '8000004W', '8000005R', '8000006W'];
tab[2] = ['8000001R', '8000002W', '8000003R', '8000004W', '8000005R', '8000006W'];
var question = {};
for (var tabIndex = 0; tabIndex < tab.length; tabIndex++) {
for (var i = 0; i < tab[tabIndex].length; i++) {
var answer = tab[tabIndex][i];
var id = answer.slice(0,7);
var ans = answer.slice(-1);
if (question[id]) {
question[id][ans] += 1;
}else {
var results = initResp(ans);
question[id] = results;
}
}
}
console.log(question);
function initResp(t) {
var results = [];
results.W = (t === 'W' ? 1 : 0);
results.R = (t === 'R' ? 1 : 0);
//console.log(results);
return results;
}
So. I have 4 for loops inside other for loops in JS, and my code appears (FireBug agrees with me) that my code is syntactically sound, and yet it refuses to work. I'm attempting to calculate the key length in a vigenere cipher through the use of the Index of Coincidence, and Kappa tests <- if that helps any.
My main problem is that the task seems to be too computationally intensive for Javascript to run, as Firefox shoots up past 1GB of memory usage, and 99% CPU when I attempt to run the keylengthfinder() function. Any ideas of how to solve this problem, even if it takes much longer to calculate, would be greatly appreciated. Here's a link to the same code - http://pastebin.com/uYPBuZZz - Sorry about any indenting issues in this code. I'm having issues putting it on the page correctly.
function indexofcoincidence(text){
text = text.split(" ").join("").toUpperCase();
var textL = text.length;
var hashtable = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (d=0; d<=25; d++) {
for (i=0; i < textL; i++){
if (text.charAt(i) === alphabet.charAt(d)){
hashtable[d] = hashtable[d] + 1;
}
}
}
var aa = hashtable[0]/textL;
var A = aa*aa;
var bb = hashtable[1]/textL;
var B = bb*bb;
var cc = hashtable[2]/textL;
var C = cc*cc;
var dd = hashtable[3]/textL;
var D = dd*dd;
var ee = hashtable[4]/textL;
var E = ee*ee;
var ff = hashtable[5]/textL;
var F = ff*ff;
var gg = hashtable[6]/textL;
var G = gg*gg;
var hh = hashtable[7]/textL;
var H = hh*hh;
var ii = hashtable[8]/textL;
var I = ii*ii;
var jj = hashtable[9]/textL;
var J = jj*jj;
var kk = hashtable[10]/textL;
var K = kk*kk;
var ll = hashtable[11]/textL;
var L = ll*ll;
var mm = hashtable[12]/textL;
var M = mm*mm;
var nn = hashtable[13]/textL;
var N = nn*nn;
var oo = hashtable[14]/textL;
var O = oo*oo;
var pp = hashtable[15]/textL;
var P = pp*pp;
var qq = hashtable[16]/textL;
var Q = qq*qq;
var rr = hashtable[17]/textL;
var R = rr*rr;
var ss = hashtable[18]/textL;
var S = ss*ss;
var tt = hashtable[19]/textL;
var T = tt*tt;
var uu = hashtable[20]/textL;
var U = uu*uu;
var vv = hashtable[21]/textL;
var V = vv*vv;
var ww = hashtable[22]/textL;
var W = ww*ww;
var xx = hashtable[23]/textL;
var X = xx*xx;
var yy = hashtable[24]/textL;
var Y = yy*yy;
var zz = hashtable[25]/textL;
var Z = zz*zz;
var Kappa = A+B+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+Z;
var Top = 0.027*textL;
var Bottom1 = 0.038*textL + 0.065;
var Bottom2 = (textL - 1)*Kappa;
var KeyLength = Top/(Bottom2 - Bottom1) ;
return Kappa/0.0385;
}
function keylengthfinder(text){
// Average Function Definition
Array.prototype.avg = function() {
var av = 0;
var cnt = 0;
var len = this.length;
for (var i = 0; i < len; i++) {
var e = +this[i];
if(!e && this[i] !== 0 && this[i] !== '0') e--;
if (this[i] == e) {av += e; cnt++;}
}
return av/cnt;
}
// Begin the Key Length Finding
var textL = text.length;
var hashtable = new Array(0,0,0,0,0,0,0,0,0,0,0,0);
for (a = 0; a <= 12; a++){ // This is the main loop, testing each key length
var stringtable = [];
for (z = 0; z <= a; z++){ // This allows each setting, ie. 1st, 4th, 7th AND 2nd, 5th, 8th to be tested
for (i = z; i < textL; i + a){
var string = '';
string = string.concat(text.charAt(i)); // Join each letter of the correct place in the string
stringtable[z] = indexofcoincidence(string);
}
}
hashtable[a] = stringtable.avg();
}
return hashtable;
}
Your problem is definitely right here
for (i = z; i < textL; i + a){
var string = '';
string = string.concat(text.charAt(i)); // Join each letter of the correct place in the string
stringtable[z] = indexofcoincidence(string);
}
Notice that if a=0 i never changes and therefore you are in an infinite loop.
Array.prototype.avg = function() {...}
should be only done once, and not every time keylengthfinder is called.
var Top = 0.027*textL;
var Bottom1 = 0.038*textL + 0.065;
var Bottom2 = (textL - 1)*Kappa;
var KeyLength = Top/(Bottom2 - Bottom1) ;
return Kappa/0.0385;
Why do you computer those variables if you don't use them at all?
var string = '';
string = string.concat(text.charAt(i)); // Join each letter of the correct place in the string
stringtable[z] = indexofcoincidence(string);
I don't know what you are trying to do in here. The string will always be only one character?
for (i = z; i < textL; i + a) {
...
stringtable[z] = ...
}
In this loop, you are computing values for i from z to textL - but you overwrite the same array item each time. So it would be enough to compute the stringtable[z] for i=textL-1 - or your algorithm is flawed.
A much shorter and more concise variant of the indexofcoincidence function:
function indexofcoincidence(text){
var l = text.replace(/ /g, "").length;
text = text.toUpperCase().replace(/[^A-Z]/g, "");
var hashtable = {};
for (var i=0; i<l; i++) {
var c = text.charAt(i);
hashtable[c] = (hashtable[c] || 0) + 1;
}
var kappa = 0;
for (var c in hashtable)
kappa += hashtable[c] * hashtable[c];
return kappa/(l*l)/0.0385;
}
All right. Now that we found your problem (including the infinite loop in case a=0, as detected by qw3n), let's rewrite the loop:
function keylengthfinder(text) {
var length = text.length,
probabilities = []; // probability by key length
maxkeylen = 13; // it might make more sense to determine this in relation to length
for (var a = 1; a <= maxkeylen; a++) { // testing each key length
var stringtable = Array(a); // strings to check with this gap
// read "a" as stringtable.length
for (var z = 0; z < a; z++) {
var string = '';
for (var i = z; i < textL; i += a) {
string += text.charAt(i);
}
// a string consisting of z, z+a, z+2a, z+3a, ... -th letters
stringtable[z] = string;
}
var sum = 0;
// summing up the coincidence indizes for current stringtable
for (var i=0; i<a; i++) {
sum += indexofcoincidence(stringtable[i]);
}
probabilities[a] = sum / a; // average
}
return probabilities;
}
Every of the loop statements has changed against your original script!
Never forget to declare the running variable to be local (var keyword)
a needs to start at zero - a key must have a minimum length of 1
to run from 1 to n, use i=1; i<=n; i++
to run from 0 to n-1, use i=0; i<n; i++ (nearly all loops, especially on zero-based array indizes).
Other loops than those two never occur in normal programs. You should get suspicious if you have loops from 0 to n or from 1 to n-1...
The update expression needs to update the running variable. i++ is a shortcut for i+=1 is a shortcut for i=i+1. Your expression, i + a, did not assign the new value (apart from the a=0 problem)!