Most efficient way to merge two arrays of objects - javascript
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/
Related
Not able to match value in a string to value in an array
I've been testing with the following code and it appears not to be functioning as expected: var obr41 = msg['OBR']['OBR.4']['OBR.4.1'].toString(); var list = ["THIS","THAT","OTHER"]; for (var i = 0, len = list.length; i < len; ++i) { if (obr41 !== list[i]) { msg['OBR']['OBR.4']['OBR.4.1'] = "NOMATCH"; break; } } If I shorten the array to just one value, then it works. Otherwise, it will return "NOMATCH" when using any of the values in the array. Any help on this would be greatly appreciated! Thank you - Matt
You are iterating over three different elements and comparing them to a single member of a an object array. If a difference is found, you break the loop and a difference will always be found because the three members are different. You probably wanted to break if a match is found and not if a match is not found var obr41 = msg['OBR']['OBR.4']['OBR.4.1'].toString(); var list = ["THIS","THAT","OTHER"]; var found = false; for (var i = 0, len = list.length; i < len; ++i) { if (obr41 === list[i]) { found = true; break; } } if(!found) msg['OBR']['OBR.4']['OBR.4.1'] = "NOMATCH";
obr41 is a single value, and the list contains three different values. That means you'll always find an item in list that does not match obr41. I think what you want is to set a variable if there's a match, and if the variable is never set, there was no match. var obr41 = msg['OBR']['OBR.4']['OBR.4.1'].toString(); var list = ["THIS","THAT","OTHER"]; var foundMatch = false; for (var i = 0, len = list.length; i < len; ++i) { if (obr41 !== list[i]) { foundMatch = true; break; } } if (!foundMatch) { msg['OBR']['OBR.4']['OBR.4.1'] = "NOMATCH"; } Or you could use .inludes() instead, which is cleaner. var obr41 = msg['OBR']['OBR.4']['OBR.4.1'].toString(); var list = ["THIS","THAT","OTHER"]; if (!list.includes(obr41)) { msg['OBR']['OBR.4']['OBR.4.1'] = "NOMATCH"; }
Need to filter out repeating consecutive characters in a string using JavaScript
It is one of the challenges in Codewars, and I am supposed to write a function that will take a string and return an array, in which I can't have two consecutive identical elements. Also, the order should not change. For example, if I pass a string "hhhhheeeelllloooooohhheeeyyy", then the function should return an array = ["h","e","l","o","h","e","y"]. This is my code. var uniqueInOrder=function(iterable){ //your code here - remember iterable can be a string or an array var unique = []; for( var i = 0; i < iterable.length; i++) { unique.push(iterable[i]); } for( var j = 0, k = 1; j < unique.length; j++, k = j + 1 ){ if(unique[j] === unique[k]){ unique.splice(k,1); } } return unique; } so, if I pass a string, such as "hhhhheeeeeellllloooo",it doesn't work as I intend it to because the value of j keeps incrementing, hence I can't filter out all the identical elements. I tried tweaking the logic, such that whenever the unique[j] === unique[k] the value of j would become zero, and if that's not the case, then things would continue as they are supposed to do. This got me an infinite loop. I need your help.
The second for loop is fail because unique.length is not constant during the run. I think your problem can be solved like this: var temp = iterable[0]; unique.push(iterable[0]); for( var i = 1; i < iterable.length; i++) { if(iterable[i] != temp) { unique.push(iterable[i]); temp = iterable[i]; } } Hope it helps!
You only need to compare the current index of iterable against the last character in unique: function(iterable){ var unique = [] for(var i=0; i< iterable.length; i++){ if(unique.length < 1){ unique.push(iterable[i]) } else if(iterable[i] !== unique[unique.length - 1]) { unique.push(iterable[i]) } } return unique }
I think this will help you: var word="hhhhheeeelllloooooohhheeeyyy" function doit(iterable){ var unique = [] unique[0]=iterable[0] for(var i=1; i< iterable.length; i++){ if(iterable[i] !== unique[unique.length - 1]) { unique.push(iterable[i]) } } return unique } alert(doit(word)) for loop will not fail because unique.length is dynamic, i.e will change with addition of new elements to array. Tested in Internet Explorer too. Here is the link to jsfiddle: https://jsfiddle.net/kannanore/z5gbee55/
var str = "hhhhheeeelllloooooohhheeeyyy"; var strLen = str.length; var newStr = ""; for(var i=0; i < strLen; i++ ){ var chr$ = str.charAt(i); //if(i==0) {newStr = chr$ }; if(chr$ == str.charAt(i+1)){ strLen = str.length;`enter code here` }else{ newStr = newStr + chr$ ; } } //document.write(newStr); console.log(newStr); //Answer: helohey
Sequential strings 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++ }
Why is `appendChild()` giving me issues?
H~ I have a script that I've been working on which will, ultimately, display Pascal's Triangle. I developed this from scratch with JavaScript, and I want to display it in the DOM. For the life of me, I can't figure out why this script produces a different effect in the DOM than it does in a console. Any help would be much appreciated! Copyright (c) 2015 Peter Gray Ward function randomScripts(){ var arr1 = ['_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_']; var arr2 = ['_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_']; var n = 0; var len = 35; var mid = Math.floor(len/2) var destination = document.getElementById("destination"); var home = document.getElementById("home"); function first(){ for(var j = 1; j<=10; j++){ var o = j%2 !== 0; var e = j%2 === 0 if(o){ for(var i = 0; i<len; i++){ odd = i%2 !== 0; if(j === 1){ arr1.splice(i,1,"_") } if(odd && (i === mid + n || i === mid - n)){ arr1.splice(i,1,1); } var node = document.createTextNode(arr1.join('')); } console.log(arr1.join('')); destination.appendChild(node); home.appendChild(node); //destination.appendChild("Please see Console for full version b/c of hackers"); } else if(e){ for(var h = 0; h<len; h++){ even = h%2 === 0; if(even && (h === mid + n || h === mid - n)){ arr2.splice(h,1,n); } } console.log(arr2.join('')); } n++; } } <p id="destination"></p>
You created functions, but you never call them. Try actually calling them to see what they do: function randomScripts(){ var arr1 = ['_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_']; var arr2 = ['_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_','_']; var n = 0; var len = 35; var mid = Math.floor(len/2) var destination = document.getElementById("destination"); var home = document.getElementById("home"); first(); function first(){ for(var j = 1; j<=10; j++){ var o = j%2 !== 0; var e = j%2 === 0 if(o){ for(var i = 0; i<len; i++){ odd = i%2 !== 0; if(j === 1){ arr1.splice(i,1,"_") } if(odd && (i === mid + n || i === mid - n)){ arr1.splice(i,1,1); } var node = document.createElement('p'); node.textContent = arr1.join(''); } console.log(arr1.join('')); destination.appendChild(node); home.appendChild(node); destination.innerHTML = "Please see Console for full version b/c of hackers"; } else if(e){ for(var h = 0; h<len; h++){ even = h%2 === 0; if(even && (h === mid + n || h === mid - n)){ arr2.splice(h,1,n); } } console.log(arr2.join('')); } n++; } } } window.addEventListener('load', randomScripts, false); <p id="destination"></p> <div id="home"></div>
There may be other problems in the script, but here are a couple I noticed. First: destination.appendChild(node); home.appendChild(node); You can't append the same node in two different places in the DOM. It will remove the first one when you append it the second time. You could either create a second text node the same way you created the first, or clone the node. Also, these two lines of code come after the if(o) statement body, but the node variable is created inside that if body. In the general case, you wouldn't expect this to work always, because node would be undefined if the if body were not executed. In your specific code, that won't happen because o is true the first time through the loop. But node only gets updated on every second pass through the loop. Is that what you want? One last thing, the indentation is not consistent, making it hard to see what is nested inside what. It's important to use correct and consistent indentation. (And I would suggest 4 spaces instead of 2 to make it easier for people to read.)
Get minimum and maximum of object property names that are integers
UPDATED (formulated the problem wrong, see note below) I have an object that has a set of properties that are named with numbers as shown in the example. The 'numbered names' are not necessarily consecutive, nor do I know where they start or end. I do know that other properties will not be named with numbers. I know that myObject["propName"] is the same as myObject.propName, but I deliberately write it in the first way because myObject.0 looks weird and doesn't get recognized by all editors. How do I get the min- and maximum array index? So in a situation like this myObject["0"] = undefined myObject["1"] = {} myObject["2"] = undefined myObject["3"] = {} myObject["4"] = {} myObject["5"] = undefined myObject["someOtherProperty"] = {} would give me this minIndex(myObject) == 1 maxIndex(myObject) == 4 To all the answers before this edit Thanks for your replies. I shouldn't have posted this question in a hurry and should have re-read it before committing. It was late and I was in a hurry. My apologies. By actually seeing my wrong statement (using an array instead of an object) I think that, based on answers for my reformulated problem, I might need to rewrite my code to use an array instead of an object. The reason I'm using an object rather then an array is material for another question. Efforts so far I have tried finding a way of converting the property names to an array and then looping through them, but that has proven cludgy. I'm kind of looking for a less error-prone and elegant way.
Edit: Aha! Now the problem becomes more interesting. Solution 1: Let's solve this in one shot, shall we? For max: function maxIndex(obj){ var max = -1; for(var i in myObject){ var val = parseInt(i); if(isFinite(val)){ if(typeof obj[val] !== 'undefined' && val > max){ max = val; } } } return max; } I think you can convert this to min on your own ;) Solution 2: Here I'll your object back into what we originally thought it was, in case you really loved one of the other solutions. Then the rest of the answer applies. function convertObject(obj){ var output = []; for(var i in myObject){ var val = parseInt(i); if(isFinite(val)){ output[val] = obj[i]; //Gotta love JS } } return output; } Continue as planned! To find the smallest, begin at the bottom and work your way up until you find it. function minIndex(myArray){ for(var i = 0; i < myArray.length; i++){ if(typeof myArray[i] !== 'undefined') return i; } } To get the biggest, start at the top. function maxIndex(myArray){ for(var i = myArray.length - 1; i >= 0; i--){ if(typeof myArray[i] !== 'undefined') return i; } } Both are worst case O(n). You can't really do better because the whole array could be empty, and you'd have to check every element to be positive. Edit: As is mentioned, you can also check if something is not undefined by simply writing if(myArray[i]). Whatever suits your fancy.
var myObject = {}; myObject["0"] = undefined; myObject["1"] = {}; myObject["2"] = undefined; myObject["3"] = {}; myObject["4"] = {}; myObject["5"] = undefined; myObject["someOtherProperty"] = {}; var keys = Object.keys(myObject).map(Number).filter(function(a){ return isFinite(a) && myObject[a]; }); var min = Math.min.apply(Math, keys); var max = Math.max.apply(Math, keys); console.log(min, max); //Logs 1 and 4 Documentation and compatibility information for all: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter
Try looping through the array until you find the 1st non-undefined element. function minIndex(arr){ for(var i = 0, len = arr.length; i < len; i++){ if(arr[i] !== undefined){ return i; } } } For max index, do the same thing, except in reverse. function maxIndex(arr){ for(var i = arr.length-1, len = 0; i >= len; i--){ if(arr[i] !== undefined){ return i; } } }
Min: for(var i = 0; i < myArray.length; i++) { if(myArray[i] != undefined) { return i; } } Max: for(var i = myArray.length-1; i >= 0; i--) { if(myArray[i] != undefined) { return i; } }
try something like this: function minIndex(var array){ for(var i = 0; i < array.length; i++) { if(typeof array[i] != "undefined") return i; } return null; } function maxIndex(var array){ var returnIndex = -1; for(var i = 0; i < array.length; i++) { if(typeof array[i] != "undefined") returnIndex = i; } if(returnIndex !== -1) return returnIndex; else return null; }
this takes advantage of the fact that for..in only iterates over defined elements, and uses the index: function minIndex(arr){ for(el in arr){return el} } function maxIndex(arr){var v; for(el in arr){v = el}; return v } CAVEATS: The second function is not very efficient though, since it loops through the entire array. This wont work if you are EXPLICITLY setting the undefined indexes.
var max=0; var min=myArray.length; for (var i in myArray) if (myArray[i]!==undefined) { max=Math.max(i, max); min=Math.min(i, min); }