Sequential strings javascript - javascript

I'm stuck on sequential string generation, the last iteration of the code below, is trying to return ac.
var charcode = 'abcdefghijklmnopqrstuvwxyz0123456789_';
var arr = [];
var len = 1;
var current = 0;
for(var i = 0; i < 40; i++) {
if(current == charcode.length) {
current = 0
len++
}
var tmpStr = ''
for(var l = 0; l < len; l++) {
tmpStr = tmpStr + charcode[current];
}
console.log(tmpStr)
current++
}
However, it produces cc.
Sorry, somehow deleted the intended output
a, b, c ... aa, ab, ac ... ba, bc, bb ... ∞
My current understanding suggests within the l < len loop I should check if len > 1 and if so break out and loop for the current charcode[x] but I just can't wrap my head around breaking in and out as it grows.

You can do it like this:
var charcode = 'abcdefghijklmnopqrstuvwxyz0123456789_';
var arr = [];
var len = 0;
var current = 0;
for(var i = 0; i < 40; i++) {
if(current == charcode.length) {
current = 0;
len++;
}
var tmpStr = (len===0) ? '' : charcode[len-1];
tmpStr = tmpStr + charcode[current];
current++;
console.log(tmpStr);
}
In brief, you didn't need a second loop, but an iteration instead (which is achieved through charcode[len-1]).
JS Bin here.
UPDATE
If you need a continuos loop until the very end of the charset, you can use this:
This one introduces a third variable (digits) to the iteration and choses a .substr() instead of a single character out of the charset, so that everytime the end of the charset is reached, another digit will be added. The variable called x sets the limit. I have tried 4000 and it looks like it is working.
var charcode = 'abcdefghijklmnopqrstuvwxyz0123456789_',
arr = [],
len = 0,
digits = 2,
current = 0,
tmpStr = '';
var x = 4000;
for(var i=0; i<x; i++) {
if(current === charcode.length) {
current = 0;
len++;
if(tmpStr.substr(0,1) === charcode.substr(-digits,1) || tmpStr === charcode.substr(-1) + '' + charcode.substr(-1)) {
len = 1;
digits++;
}
}
if(digits === charcode.length) {
console.log(charcode);
console.log(i + ' results found');
break;
}
tmpStr = (len===0) ? '' : charcode.substr([len-1], digits-1);
tmpStr += charcode[current];
current++;
console.log(tmpStr);
}
Final JS Bin here.

Unless I'm failing to understand your question, which is highly likely, functional programming solves this problem in an incredibly easy way
const stringSequence = xs =>
flatMap (x => map (add (x)) (xs)) (xs);
let chars = 'abcdefghijklmnopqrstuvwxyz0123456789_'
console.log (stringSequence (chars));
// ["aa","ab","ac","ad","ae","af","ag","ah","ai","aj","ak","al","am","an","ao","ap","aq","ar","as","at","au","av","aw","ax","ay","az","a0","a1","a2","a3","a4","a5","a6","a7","a8","a9","a_","ba","bb","bc","bd","be","bf","bg","bh","bi","bj","bk","bl","bm","bn","bo","bp","bq","br","bs","bt","bu","bv","bw","bx","by","bz","b0","b1","b2","b3","b4","b5","b6","b7","b8","b9","b_","ca","cb","cc","cd","ce","cf","cg","ch","ci","cj","ck","cl","cm","cn","co","cp","cq","cr","cs","ct","cu","cv","cw","cx","cy","cz","c0","c1","c2","c3","c4","c5","c6","c7","c8","c9","c_","da","db","dc","dd","de","df","dg","dh","di","dj","dk","dl","dm","dn","do","dp","dq","dr","ds","dt","du","dv","dw","dx","dy","dz","d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","d_","ea","eb","ec","ed","ee","ef","eg","eh","ei","ej","ek","el","em","en","eo","ep","eq","er","es","et","eu","ev","ew","ex","ey","ez","e0","e1","e2","e3","e4","e5","e6","e7","e8","e9","e_","fa","fb","fc","fd","fe","ff","fg","fh","fi","fj","fk","fl","fm","fn","fo","fp","fq","fr","fs","ft","fu","fv","fw","fx","fy","fz","f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","f_","ga","gb","gc","gd","ge","gf","gg","gh","gi","gj","gk","gl","gm","gn","go","gp","gq","gr","gs","gt","gu","gv","gw","gx","gy","gz","g0","g1","g2","g3","g4","g5","g6","g7","g8","g9","g_","ha","hb","hc","hd","he","hf","hg","hh","hi","hj","hk","hl","hm","hn","ho","hp","hq","hr","hs","ht","hu","hv","hw","hx","hy","hz","h0","h1","h2","h3","h4","h5","h6","h7","h8","h9","h_","ia","ib","ic","id","ie","if","ig","ih","ii","ij","ik","il","im","in","io","ip","iq","ir","is","it","iu","iv","iw","ix","iy","iz","i0","i1","i2","i3","i4","i5","i6","i7","i8","i9","i_","ja","jb","jc","jd","je","jf","jg","jh","ji","jj","jk","jl","jm","jn","jo","jp","jq","jr","js","jt","ju","jv","jw","jx","jy","jz","j0","j1","j2","j3","j4","j5","j6","j7","j8","j9","j_","ka","kb","kc","kd","ke","kf","kg","kh","ki","kj","kk","kl","km","kn","ko","kp","kq","kr","ks","kt","ku","kv","kw","kx","ky","kz","k0","k1","k2","k3","k4","k5","k6","k7","k8","k9","k_","la","lb","lc","ld","le","lf","lg","lh","li","lj","lk","ll","lm","ln","lo","lp","lq","lr","ls","lt","lu","lv","lw","lx","ly","lz","l0","l1","l2","l3","l4","l5","l6","l7","l8","l9","l_","ma","mb","mc","md","me","mf","mg","mh","mi","mj","mk","ml","mm","mn","mo","mp","mq","mr","ms","mt","mu","mv","mw","mx","my","mz","m0","m1","m2","m3","m4","m5","m6","m7","m8","m9","m_","na","nb","nc","nd","ne","nf","ng","nh","ni","nj","nk","nl","nm","nn","no","np","nq","nr","ns","nt","nu","nv","nw","nx","ny","nz","n0","n1","n2","n3","n4","n5","n6","n7","n8","n9","n_","oa","ob","oc","od","oe","of","og","oh","oi","oj","ok","ol","om","on","oo","op","oq","or","os","ot","ou","ov","ow","ox","oy","oz","o0","o1","o2","o3","o4","o5","o6","o7","o8","o9","o_","pa","pb","pc","pd","pe","pf","pg","ph","pi","pj","pk","pl","pm","pn","po","pp","pq","pr","ps","pt","pu","pv","pw","px","py","pz","p0","p1","p2","p3","p4","p5","p6","p7","p8","p9","p_","qa","qb","qc","qd","qe","qf","qg","qh","qi","qj","qk","ql","qm","qn","qo","qp","qq","qr","qs","qt","qu","qv","qw","qx","qy","qz","q0","q1","q2","q3","q4","q5","q6","q7","q8","q9","q_","ra","rb","rc","rd","re","rf","rg","rh","ri","rj","rk","rl","rm","rn","ro","rp","rq","rr","rs","rt","ru","rv","rw","rx","ry","rz","r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r_","sa","sb","sc","sd","se","sf","sg","sh","si","sj","sk","sl","sm","sn","so","sp","sq","sr","ss","st","su","sv","sw","sx","sy","sz","s0","s1","s2","s3","s4","s5","s6","s7","s8","s9","s_","ta","tb","tc","td","te","tf","tg","th","ti","tj","tk","tl","tm","tn","to","tp","tq","tr","ts","tt","tu","tv","tw","tx","ty","tz","t0","t1","t2","t3","t4","t5","t6","t7","t8","t9","t_","ua","ub","uc","ud","ue","uf","ug","uh","ui","uj","uk","ul","um","un","uo","up","uq","ur","us","ut","uu","uv","uw","ux","uy","uz","u0","u1","u2","u3","u4","u5","u6","u7","u8","u9","u_","va","vb","vc","vd","ve","vf","vg","vh","vi","vj","vk","vl","vm","vn","vo","vp","vq","vr","vs","vt","vu","vv","vw","vx","vy","vz","v0","v1","v2","v3","v4","v5","v6","v7","v8","v9","v_","wa","wb","wc","wd","we","wf","wg","wh","wi","wj","wk","wl","wm","wn","wo","wp","wq","wr","ws","wt","wu","wv","ww","wx","wy","wz","w0","w1","w2","w3","w4","w5","w6","w7","w8","w9","w_","xa","xb","xc","xd","xe","xf","xg","xh","xi","xj","xk","xl","xm","xn","xo","xp","xq","xr","xs","xt","xu","xv","xw","xx","xy","xz","x0","x1","x2","x3","x4","x5","x6","x7","x8","x9","x_","ya","yb","yc","yd","ye","yf","yg","yh","yi","yj","yk","yl","ym","yn","yo","yp","yq","yr","ys","yt","yu","yv","yw","yx","yy","yz","y0","y1","y2","y3","y4","y5","y6","y7","y8","y9","y_","za","zb","zc","zd","ze","zf","zg","zh","zi","zj","zk","zl","zm","zn","zo","zp","zq","zr","zs","zt","zu","zv","zw","zx","zy","zz","z0","z1","z2","z3","z4","z5","z6","z7","z8","z9","z_","0a","0b","0c","0d","0e","0f","0g","0h","0i","0j","0k","0l","0m","0n","0o","0p","0q","0r","0s","0t","0u","0v","0w","0x","0y","0z","00","01","02","03","04","05","06","07","08","09","0_","1a","1b","1c","1d","1e","1f","1g","1h","1i","1j","1k","1l","1m","1n","1o","1p","1q","1r","1s","1t","1u","1v","1w","1x","1y","1z","10","11","12","13","14","15","16","17","18","19","1_","2a","2b","2c","2d","2e","2f","2g","2h","2i","2j","2k","2l","2m","2n","2o","2p","2q","2r","2s","2t","2u","2v","2w","2x","2y","2z","20","21","22","23","24","25","26","27","28","29","2_","3a","3b","3c","3d","3e","3f","3g","3h","3i","3j","3k","3l","3m","3n","3o","3p","3q","3r","3s","3t","3u","3v","3w","3x","3y","3z","30","31","32","33","34","35","36","37","38","39","3_","4a","4b","4c","4d","4e","4f","4g","4h","4i","4j","4k","4l","4m","4n","4o","4p","4q","4r","4s","4t","4u","4v","4w","4x","4y","4z","40","41","42","43","44","45","46","47","48","49","4_","5a","5b","5c","5d","5e","5f","5g","5h","5i","5j","5k","5l","5m","5n","5o","5p","5q","5r","5s","5t","5u","5v","5w","5x","5y","5z","50","51","52","53","54","55","56","57","58","59","5_","6a","6b","6c","6d","6e","6f","6g","6h","6i","6j","6k","6l","6m","6n","6o","6p","6q","6r","6s","6t","6u","6v","6w","6x","6y","6z","60","61","62","63","64","65","66","67","68","69","6_","7a","7b","7c","7d","7e","7f","7g","7h","7i","7j","7k","7l","7m","7n","7o","7p","7q","7r","7s","7t","7u","7v","7w","7x","7y","7z","70","71","72","73","74","75","76","77","78","79","7_","8a","8b","8c","8d","8e","8f","8g","8h","8i","8j","8k","8l","8m","8n","8o","8p","8q","8r","8s","8t","8u","8v","8w","8x","8y","8z","80","81","82","83","84","85","86","87","88","89","8_","9a","9b","9c","9d","9e","9f","9g","9h","9i","9j","9k","9l","9m","9n","9o","9p","9q","9r","9s","9t","9u","9v","9w","9x","9y","9z","90","91","92","93","94","95","96","97","98","99","9_","_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","_0","_1","_2","_3","_4","_5","_6","_7","_8","_9","__"]
Oh but you don't have flatMap? Easy, just make your own, as well as any other simple procedures that describe the computations you would like to perform
const add = x => y => x + y;
const map = f => xs =>
Array.prototype.map.call(xs, x => f (x));
const reduce = f => i => xs =>
Array.prototype.reduce.call(xs, (x,y) => f (x) (y));
const concat = xs => x =>
xs.concat(x);
const flatMap = f => xs =>
reduce (concat) ([]) (map (f) (xs));
These procedures are highly reusable and free you from the shackles of imperative code that looks like this
var charcode = 'abcdefghijklmnopqrstuvwxyz0123456789_';
// setup several state variables
var arr = [];
var len = 1; // 6 months later, why did we initialize len at 1?
var current = 0;
// manual looping, with arbitrary static input of 40 (why 40?)
for(var i = 0; i < 40; i++) {
// logic with potential for human error
if(current == charcode.length) {
// variable mutations
current = 0
len++
}
// temporary variables
var tmpStr = ''
// move manual looping
for(var l = 0; l < len; l++) {
// more variable mutation
tmpStr = tmpStr + charcode[current];
}
// IO side effects
console.log(tmpStr)
// manual iteration
current++
}

Related

Character with longest consecutive repetition

i think i have wirtten the correct code for the problem only one thing and it that i return the first longest sequence how can i alter that to return the last maximum sequence?
an example from codewars editor :
for input '00000000000000111111111111111112222222222222223333333333333344444444444445555555555555666666666666777777777777888888888888888999999999999999999aaaaaaaaabbbbbbbbbbbbbbbbcccccccccccccccccccdddddddddddddddddddeeeeeeeeeeeeeeefffffffffffffggggggggggggggghhhhhhhhhhhhhiiiiiiiiiijjjjjjjjjjjjjjkkkkkkkkkkkkllllllllllmmmmmmmmmmnnnnnnnnnnnnnnoooooooooooopppppppppppppppppqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrssssssssssttttttttttttuuuuuuvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyzzzzzzzzzzzzzz'
Expected: ['c', 19], instead got: ['0', 19]
here is my code:
function longestRepetition(s) {
var count = 0;
var temp = s.charAt(0);
var arr = [];
for (var i = 0; i < s.length; i++) {
if (temp === s.charAt(i)) {
count++
temp = s.charAt(i)
}
else {
temp = s.charAt(i);
arr.push(count)
count = 1;
}
if(i==s.length-1)
arr.push(count);
}
if(arr.length>0)
{
var Max=arr[0]
for(var i=0;i<arr.length;i++)
{
if(Max<=arr[i])
Max=arr[i];
}
}
else var Max=0;
var mindex=arr.indexOf(Max);
return [s.charAt(mindex),Max]
}
I think this would be easier with a regular expression. Match any character, then backreference that character as many times as you can.
Then, you'll have an array of all the sequential sequences, eg ['000', 'aaaaa']. Map each string to its length and pass into Math.max, and you'll know how long the longest sequence is.
Lastly, filter the sequences by those which have that much length, and return the last item in the filtered array:
function longestRepetition(s) {
const repeatedChars = s.match(/(.)\1*/g);
const longestLength = Math.max(...repeatedChars.map(str => str.length));
const longestChars = repeatedChars.filter(str => str.length === longestLength);
return [longestChars.pop(), longestLength];
}
console.log(longestRepetition('00000000000000111111111111111112222222222222223333333333333344444444444445555555555555666666666666777777777777888888888888888999999999999999999aaaaaaaaabbbbbbbbbbbbbbbbcccccccccccccccccccdddddddddddddddddddeeeeeeeeeeeeeeefffffffffffffggggggggggggggghhhhhhhhhhhhhiiiiiiiiiijjjjjjjjjjjjjjkkkkkkkkkkkkllllllllllmmmmmmmmmmnnnnnnnnnnnnnnoooooooooooopppppppppppppppppqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrssssssssssttttttttttttuuuuuuvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyzzzzzzzzzzzzzz'));
The issue in your code is that minindex is an index in your arr, but that index has nothing to do with s. So s.charAt(minindex) makes no sense. You should maintain for which character you had found the count. For instance you could push in arr both the count and the corresponding character (as a subarray with two values). Then the rest of your code would only need little modification to make it work.
Applying this idea to your code without changing anything else, we get this:
function longestRepetition(s) {
var count = 0;
var temp = s.charAt(0);
var arr = [];
for (var i = 0; i < s.length; i++) {
if (temp === s.charAt(i)) {
count++
temp = s.charAt(i) // Not necessary: was already equal
}
else {
arr.push([temp, count]); // <--- pair, BEFORE changing temp
temp = s.charAt(i);
count = 1;
}
if(i==s.length-1)
arr.push([temp, count]); // <---
}
if(arr.length>0)
{
var Max=arr[0]; // <-- Max is now a pair of char & count
for(var i=0;i<arr.length;i++)
{
if(Max[1]<arr[i][1]) // Comparison changed to just less-than
Max=arr[i];
}
}
else Max=[null, 0]; // Must be a pair here also
return Max; // Just return the pair
}
console.log(longestRepetition('00000000000000111111111111111112222222222222223333333333333344444444444445555555555555666666666666777777777777888888888888888999999999999999999aaaaaaaaabbbbbbbbbbbbbbbbcccccccccccccccccccdddddddddddddddddddeeeeeeeeeeeeeeefffffffffffffggggggggggggggghhhhhhhhhhhhhiiiiiiiiiijjjjjjjjjjjjjjkkkkkkkkkkkkllllllllllmmmmmmmmmmnnnnnnnnnnnnnnoooooooooooopppppppppppppppppqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrssssssssssttttttttttttuuuuuuvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyzzzzzzzzzzzzzz'));
But you can do the same with less code:
function longestRepetition(s) {
let result = [null, 0]; // pair of character and count
for (var i = 0; i < s.length; null) {
let start = i++;
while (i < s.length && s[i] === s[start]) i++; // Find end of series
if (i - start > result[1]) result = [s[start], i - start];
}
return result;
}
console.log(longestRepetition('00000000000000111111111111111112222222222222223333333333333344444444444445555555555555666666666666777777777777888888888888888999999999999999999aaaaaaaaabbbbbbbbbbbbbbbbcccccccccccccccccccdddddddddddddddddddeeeeeeeeeeeeeeefffffffffffffggggggggggggggghhhhhhhhhhhhhiiiiiiiiiijjjjjjjjjjjjjjkkkkkkkkkkkkllllllllllmmmmmmmmmmnnnnnnnnnnnnnnoooooooooooopppppppppppppppppqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrssssssssssttttttttttttuuuuuuvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyzzzzzzzzzzzzzz'));
The solution below answers the question with O(n) runtime:
function longestRepetition(s) {
let count = s.length > 0 ? 1 : 0
let char = s.length > 0 ? s[0] : ''
for (let string_i = 0; string_i < s.length - 1; string_i += 1) {
// keep track of current_char
let current_char = s[string_i]
let next_char = s[string_i + 1]
// while the next char is same as current_char
let tracker = 1
while (current_char === next_char) {
// add one to tracker
tracker += 1
string_i += 1
next_char = s[string_i + 1]
}
// if tracker greater than count
if (tracker > count) {
// returned char = current char
// count =tracker
count = tracker;
char = current_char;
}
}
return [char, count]
}
console.log(longestRepetition("bbbaaabaaaa"))//, ["a",4]

Find all permutations of smaller string s in string b (JavaScript)

I've been trying to find a O(n) solution to the following problem: Find the number of anagrams (permutations) of string s in string b, where s.length will always be smaller than b.length
I read that the optimal solution involves keeping track of the frequencies of the characters in the smaller string and doing the same for the sliding window as it moves across the larger string, but I'm not sure how that implementation actually works. Right now my solution doesn't work (see comments) but even if it did, it would take O(s + sn) time.
EDIT: Sample input: ('aba', 'abaab'). Output: 3, because 'aba' exists in b starting at index 0, and 'baa' at 1, and 'aab' at 2.
function anagramsInStr(s,b) {
//O(s)
let freq = s.split("").reduce((map, el) => {
map[el] = (map[el] + 1) || 1;
return map;
}, {});
let i = 0, j = s.length;
// O(n)
for (let char in b.split("")) {
// O(s)
if (b.length - char + 1 > s.length) {
let window = b.slice(i,j);
let windowFreq = window.split("").reduce((map, el) => {
map[el] = (map[el] + 1) || 1;
return map;
}, {});
// Somewhere about here compare the frequencies of chars found in the window to the frequencies hash defined in the outer scope.
i++;
j++;
}
}
}
Read through the comments and let me know if you have any questions:
function countAnagramOccurrences(s, b) {
var matchCount = 0;
var sCounts = {}; // counts for the letters in s
var bCounts = {}; // counts for the letters in b
// construct sCounts
for (var i = 0; i < s.length; i++) {
sCounts[s[i]] = (sCounts[s[i]] || 0) + 1;
}
// all letters that occur in sCounts
var letters = Object.keys(sCounts);
// for each letter in b
for (var i = 0; i < b.length; i++) {
// maintain a sliding window
// if we already have s.length items in the counts, remove the oldest one
if (i >= s.length) {
bCounts[b[i-s.length]] -= 1;
}
// increment the count for the letter we're currently looking at
bCounts[b[i]] = (bCounts[b[i]] || 0) + 1;
// test for a match (b counts == s counts)
var match = true;
for (var j = 0; j < letters.length; j++) {
if (sCounts[letters[j]] !== bCounts[letters[j]]) {
match = false;
break;
}
}
if (match) {
matchCount += 1;
}
}
return matchCount;
}
console.log(countAnagramOccurrences('aba', 'abaab')); // 3
EDIT
A note about the runtime: this is sort of O(nk + m), where n is the length of s, m is the length of b, and k is the number of unique characters in b. Since m is always less than n, we can reduce to O(nk), and since k is bounded by a fixed constant (the size of the alphabet), we can further reduce to O(n).

Find all lowercase and uppercase combinations of a string in Javascript

I am looking for this stackoverflow question to be answered in Javascript.
So if my input is "word", the function should return:
word,
Word,
wOrd,
WOrd,
woRd,
WoRd,
etc..
here's what i have so far but it only produces the permutations (doesn't capitalize anything)
var perm = function(str){
var results = [];
var combos = function(reference, appendTo){
appendTo = appendTo || "";
if(reference.length === 0) {
results.push(appendTo);
}
for(var i = 0; i < reference.length; i++){
var current = reference.splice(i, 1);
combos(reference, appendTo+current);
reference.splice(i, 0, current)
}
}
combos(str.split(""));
return results;
}
perm("word");
One option would be generating capitalization permutations via binary logic.
As a simple example of the snippet below, consider the following table where the left column is the binary representation of the current permutation and the right column is the resulting capitalization:
0000 | word
1000 | Word
0100 | wOrd
1100 | WOrd
...
1111 | WORD
// Used to display the results
const write = (msg) => {
document.body.appendChild(document.createElement('div')).innerHTML = msg;
};
const input = "word";
const letters = input.split("");
const permCount = 1 << input.length;
for (let perm = 0; perm < permCount; perm++) {
// Update the capitalization depending on the current permutation
letters.reduce((perm, letter, i) => {
letters[i] = (perm & 1) ? letter.toUpperCase() : letter.toLowerCase();
return perm >> 1;
}, perm);
const result = letters.join("");
write(result);
}
Note that theoretically this approach would work all the way up to Number.MAX_SAFE_INTEGER, up to inputs of length 52, but realistically you'll run into performance issues.
var s = "word";
var sp = s.split("");
for (var i = 0, l = 1 << s.length; i < l; i++) {
for (var j = i, k = 0; j; j >>= 1, k++) {
sp[k] = (j & 1) ? sp[k].toUpperCase() : sp[k].toLowerCase();
}
var st = sp.join("");
var d = document.createElement("p");
d.appendChild(document.createTextNode(st));
document.body.appendChild(d);
}
With Nit's solution in mind, I wanted to offer a slightly refactored solution that may be easier to follow
var perm = function(str){
var results = [];
var arr = str.split("");
var len = Math.pow(arr.length, 2);
for( var i = 0; i < len; i++ ){
for( var k= 0, j = i; k < arr.length; k++, j >>=1){
arr[k] = ( j & 1 ) ? arr[k].toUpperCase() : arr[k].toLowerCase();
}
var combo = arr.join("");
results.push(combo);
}
return results;
}
perm("word");
// NOT AN ANWSER JUST WANT TO RUN CODE ON CHROMEBOOK
// Used to display the results
const write = (msg) => {
document.body.appendChild(document.createElement('div')).innerHTML = msg;
};
const input = "word";
const letters = input.split("");
const permCount = 1 << input.length;
for (let perm = 0; perm < permCount; perm++) {
// Update the capitalization depending on the current permutation
letters.reduce((perm, letter, i) => {
letters[i] = (perm & 1) ? letter.toUpperCase() : letter.toLowerCase();
return perm >> 1;
}, perm);
const result = letters.join("");
write(result);
}

JavaScript procedure to find the characters that are in one string but not in another

I'e been trying to write one and it's getting messy!
Suppose I have two strings textStart, textTarget and I want to keep track of the characters I would need to add and remove from textStart in order to product textTarget.
For instance, if textStart = "dude" and textTarget = "deck", then characters that would need to be added would be 'c' and 'k' and the characters that would need to be substracted would be the 'u' and one of the 'd's.
I'm thinking that I first need to create maps that represent the number of each character in textStart and textTarget.
So I wrote this:
var startChars = {};
for (var k = 0, n = textStart.length; k < n; ++k)
{
if (textStart[k] in startChars)
++startChars[textStart[k]];
else
startChars[textStart[k]] = 1;
}
var targetChars = {};
for (var k = 0, n = textTarget.length; k < n; ++k)
{
if (textTarget[k] in startChars)
++targetChars[textTarget[k]];
else
map1[targetChars[k]] = 1;
}
Which would give me
startChars['d']=2,
startChars['u']=1,
startChars['e']=1
and
targetChars['d']=1,
targetChars['e']=1,
targetChars['c']=1,
targetChars['k']=1
Then I can make create maps needAdded and needRemoved that look at the difference in the above two maps:
var needAdded = {};
var needRemoved = {};
I'm not sure how to fill those maps as intended, because I don't know how to iterate through the keys of a map using JavaScript. I somehow need to end up with
needAdded['c']=1,
needAdded['k']=1,
needRemoved['u']=1,
needRemoved['d']=1
That's where you guys come in and help me.
I hope I've done a good job describing what I'm trying to do and how I've tried to do it so far. My programming intuition tells me that I'm writing too many lines of code and that I need to consult StackOverflow for help. Any way to do this elegantly without JQuery or Regex? I know someone's going to come in this thread and write a 1-line Regex solution or something like that.
var s = 'dude',
t = 'deck',
finalOutput = '';
for (var i = 0; i < s.length; i++){
if ( typeof t[i] != 'undefined' ){
if ( s[i] != t[i] ){
console.log(s[i] + ' changed to ' + t[i]);
s[i] = t[i];
finalOutput += t[i];
} else{
finalOutput += s[i];
}
}
}
console.log('FINAL: ' + finalOutput);
Here's a jsfiddle I just spent way too much time on... hopefully it makes sense :)
var textStart = 'dude';
var textTarget = 'deck';
var startChars = {};
for (var k = 0, n = textStart.length; k < n; ++k)
{
if (textStart[k] in startChars)
++startChars[textStart[k]];
else
startChars[textStart[k]] = 1;
}
var targetChars = {};
for (var k = 0, n = textTarget.length; k < n; ++k)
{
if (textTarget[k] in targetChars)
++targetChars[textTarget[k]];
else
targetChars[textTarget[k]] = 1;
}
console.log('start: ' + JSON.stringify(startChars));
console.log('target: ' + JSON.stringify(targetChars));
var needAdded = {};
var needRemoved = {};
for (var c in startChars) {
// If target does not contain letter, remove all, otherwise remove excess
if (targetChars[c] > 0) {
if (startChars[c] > targetChars[c])
needRemoved[c] = startChars[c] - targetChars[c];
else if (startChars[c] < targetChars[c])
needAdded[c] = targetChars[c] - startChars[c];
} else {
needRemoved[c] = startChars[c];
}
}
for (var c in targetChars) {
// If start does not contain letter, add all, otherwise add excess
if (startChars[c] > 0) {
if (startChars[c] > targetChars[c])
needRemoved[c] = startChars[c] - targetChars[c];
else if (startChars[c] < targetChars[c])
needAdded[c] = targetChars[c] - startChars[c];
} else {
needAdded[c] = targetChars[c];
}
}
console.log('needAdded: ' + JSON.stringify(needAdded));
console.log('needRemoved: ' + JSON.stringify(needRemoved));
The output is as follows:
start: {"d":2,"u":1,"e":1}
target: {"d":1,"e":1,"c":1,"k":1}
needAdded: {"c":1,"k":1}
needRemoved: {"d":1,"u":1}
Ok, also too much time on this:
var textStart = "dude";
var textTarget = "duck";
var map = {};
MapCharacters(textStart, map, 1);
MapCharacters(textTarget, map, -1);
console.log(map);
var toDelete = [];
var toAdd = [];
for (var prop in map) {
if (map.hasOwnProperty(prop)) {
while (map[prop] > 0) {
toDelete.push(prop);
map[prop]--;
}
while (map[prop] < 0) {
toAdd.push(prop);
map[prop]++;
}
}
}
console.log(toDelete);
console.log(toAdd);
function MapCharacters(string, map, add) {
for (var k = 0, n = string.length; k < n; ++k) {
if (string[k] in map) {
map[string[k]] += add;
} else {
map[string[k]] = add;
}
}
}
http://jsfiddle.net/nSV2J/1/
It could probably be done more efficiently, but as I said - too much time!
I realized that the best way to do this is not to make two maps, but just one. In the first case you increment the count for each letter and in the second case you decrease it. Now it's easy to find which ones need to be removed (the ones that end up > 0) and which ones need to be added (the ones that end up < 0)

Most efficient way to merge two arrays of objects

I've already solved this out. However I'm looking for a faster solution since my variables has thousands of objects.
I have two arrays like this:
var full = [{a:'aa1',b:'bb1'},{a:'aa3',b:'bb2'},{a:'aa3',b:'bb3'},{a:'aa2',b:'bb3'}],
some = [{a:'aa1',b:'bb1'},{a:'aa3',b:'bb3'}];
I'm trying to flag in a new attribute called c in full if the object exist on some. Expected result:
[{a:'aa1',b:'bb1',c:true},{a:'aa3',b:'bb2'},{a:'aa3',b:'bb3',c:true},{a:'aa2',b:'bb3'}]
Some important tips:
some always has less elements than full
both arrays are sorted equal
My current approach is:
var getIndexByAB = function(arr, a,b){
var initialIndex = getIndexByAB.initialIndex || 0,
len = arr.length;
for(initialIndex; initialIndex < len ;initialIndex++ ){
var el = arr[initialIndex];
if( el.b === b && el.a === a ){
getIndexByAB.initialIndex = initialIndex;
return initialIndex;
}
}
return -1;
}
var len = some.length;
for(var i = 0; i < len ; i++){
var el=some[i],
index = getIndexByAB(full,el.a,el.b);
if(index > -1) full[index].c = true;
}
UPDADE: original solution improved using Juan comment.
Since they are sorted, you can just pass an index to start the search from, that will avoid the O(n^2). You were already doing it, but by storing the index in a global variable. Instead, you should pass it as an argument to getIndexByAB.
function getIndexByAB(arr, a,b , initialIndex){
// Was tracking last index by storing it in a global 'this.initialIndex'.
// 'this' points to 'window' in global functions. That's bad, it
// means this function can't be called on different arrays without
// resetting the global
// var initialIndex = this.initialIndex || 0,
initialIndex = initialIndex || 0;
var len = arr.length;
for(initialIndex; initialIndex < len ; initialIndex++ ){
var el = arr[initialIndex];
if( el.b === b && el.a === a ){
// Bad globals
// this.initialIndex = initialIndex;
return initialIndex;
}
}
return -1;
}
var len = some.length;
var lastValidIndex = 0;
for(var i = 0; i < len ; i++){
var el = some[i];
// Pass the index here, so it doesn't start from scratch
var index = getIndexByAB(full, el.a, el.b, lastValidIndex);
if(index > -1) {
full[index].c = true;
lastValidIndex = index;
}
}
By the way, if you do want a function to cache some values, here's how to do it avoiding globals. (Not that you should use it in this case)
var getIndexByAB = (function(){
// This will only be executed once, and is private
// to getIndexByAB (all invocations)
var lastGoodIndex = 0;
return function(arr, a,b, resetIndex){
if (resetIndex) {
lastGoodIndex = 0;
}
var len = arr.length;
for(var index = lastGoodIndex; index < len ; index++ ){
var el = arr[index];
if( el.b === b && el.a === a ){
lastGoodIndex = index;
return index;
}
}
return -1;
};
})();
Alternatively, you could achieve the following by caching it in getIndexByAB.initialIndex but it's not very elegant. The main reason for avoiding this is the fact that getIndexByAB.initialIndex can be modified by anybody else
Since the arrays are both sorted and some is strictly smaller than full, you could save some time by traversing both arrays at the same time with different indexes. As it is, you are traversing full to get the index of the matching element each time, so you have O(N^2) running time, but you only need to continue the search from the last element you matched.
Not as efficient as #Juan's answer (which takes advantage of the sorted nature, among other things), but I thought I'd still present my solution as it incidentally forced me to come up with a solution for cloning and comparing Javacript objects.
Utilities
// Create a copy of x without reference back to x
function clone(x){
return JSON.parse(JSON.stringify(x));
}
// Pass any number of arguments of any type. Returns true if they are all identical.
function areEqual(){
for(var i = 1, l = arguments.length, x = JSON.stringify(arguments[0]); i < arguments.length; ++i){
if(x !== JSON.stringify(arguments[i])){
return false;
}
}
return true;
}
Flagging function
// Your flagLabel being 'c'
function matchAndFlagWith(flagLabel,aFull,aSome){
var aFlagged = clone(aFull);
for(var i1 = 0, l1 = aSome.length, oSome; oSome = aSome[i1], i1 < l1; ++i1){
for(var i2 = 0, l2 = aFlagged.length, oFlagged; oFlagged = aFlagged[i2], i2 < l2; ++i2){
if(areEqual(oFlagged,oSome)){
oFlagged[flagLabel] = true;
}
}
}
return aFlagged;
}
Demo
http://jsfiddle.net/barney/p2qsG/

Categories