From: Garrett Smith on 13 Jan 2010 12:04 Thomas 'PointedEars' Lahn wrote: > David Mark wrote: > >> Thomas 'PointedEars' Lahn wrote: >>> David Mark wrote: >>>> Scott Sauyet wrote: >>>>> var photos = [], captions = []; >>>>> for (var i = 0, len = library.length; i < len; i++) { >>>>> photos.push(library[i]["img"]); >>>>> captions.push(library[i]["caption"]); >>>>> } >>>> var photos = [], captions = []; >>>> photos.length = captions.length = library.length; >>>> for (var i = 0, len = library.length; i--;) { > ^^^^^ ^^^ >>> No :) >> No? Perhaps you meant you could improve on it? > > If "to improve" means "let it do anything useful", then yes. Long night? > ;-) > >>>> photos[i] = library[i]["img"]; >>>> captions[i] = library[i]["caption"]; >>>> } >>> var >>> photos = [], >>> captions = [], >>> len = library.length; >>> >>> photos.length = captions.length = len; >>> >>> for (var i = len; i--;) >>> { >>> var o = library[i]; >>> photos[i] = o.img; >>> captions[i] = o.caption; >>> } >> Yes, the start's a bit nicer (library length). I don't know if that >> assignment to o will help though. You only saved two lookups. Not >> worth worrying about it at this point. > > Benchmarks suggest it would be about 20% faster in TraceMonkey 1.9.1.6. > Setting the length will avoid step 10 in array [[Put]], so should be fastest. IE versions may benefit even more from this. -- Garrett comp.lang.javascript FAQ: http://jibbering.com/faq/
From: David Mark on 13 Jan 2010 12:10 Garrett Smith wrote: > Thomas 'PointedEars' Lahn wrote: >> David Mark wrote: >> >>> Thomas 'PointedEars' Lahn wrote: >>>> David Mark wrote: >>>>> Scott Sauyet wrote: >>>>>> var photos = [], captions = []; >>>>>> for (var i = 0, len = library.length; i < len; i++) { >>>>>> photos.push(library[i]["img"]); >>>>>> captions.push(library[i]["caption"]); >>>>>> } >>>>> var photos = [], captions = []; >>>>> photos.length = captions.length = library.length; >>>>> for (var i = 0, len = library.length; i--;) { >> ^^^^^ ^^^ >>>> No :) >>> No? Perhaps you meant you could improve on it? >> >> If "to improve" means "let it do anything useful", then yes. Long >> night? ;-) Yes. Typo. Was supposed to be for (var i = library.length; i--;) .... and I didn't notice Thomas fixed that either. Bleary-eyed after reading a bunch of (typically) horrible JS overnight. Why do the worst programmers in the world write seemingly all of the "major" JS. It's just not sustainable, so I think we'll all end up programming ES in Flash or the like. >> >>>>> photos[i] = library[i]["img"]; >>>>> captions[i] = library[i]["caption"]; >>>>> } >>>> var >>>> photos = [], >>>> captions = [], >>>> len = library.length; >>>> >>>> photos.length = captions.length = len; >>>> >>>> for (var i = len; i--;) >>>> { >>>> var o = library[i]; >>>> photos[i] = o.img; >>>> captions[i] = o.caption; >>>> } >>> Yes, the start's a bit nicer (library length). I don't know if that >>> assignment to o will help though. You only saved two lookups. Not >>> worth worrying about it at this point. >> >> Benchmarks suggest it would be about 20% faster in TraceMonkey 1.9.1.6. >> > Setting the length will avoid step 10 in array [[Put]], so should be > fastest. IE versions may benefit even more from this. But, as Thomas noted, it will be set (for good) the first time as we are going backwards.
From: David Mark on 13 Jan 2010 12:10 Garrett Smith wrote: > Thomas 'PointedEars' Lahn wrote: >> David Mark wrote: >> >>> Thomas 'PointedEars' Lahn wrote: >>>> David Mark wrote: >>>>> Scott Sauyet wrote: >>>>>> var photos = [], captions = []; >>>>>> for (var i = 0, len = library.length; i < len; i++) { >>>>>> photos.push(library[i]["img"]); >>>>>> captions.push(library[i]["caption"]); >>>>>> } >>>>> var photos = [], captions = []; >>>>> photos.length = captions.length = library.length; >>>>> for (var i = 0, len = library.length; i--;) { >> ^^^^^ ^^^ >>>> No :) >>> No? Perhaps you meant you could improve on it? >> >> If "to improve" means "let it do anything useful", then yes. Long >> night? ;-) Yes. Typo. Was supposed to be for (var i = library.length; i--;) .... and I didn't notice Thomas fixed that either. Bleary-eyed after reading a bunch of (typically) horrible JS overnight. Why do the worst programmers in the world write seemingly all of the "major" JS. It's just not sustainable, so I think we'll all end up programming ES in Flash or the like. >> >>>>> photos[i] = library[i]["img"]; >>>>> captions[i] = library[i]["caption"]; >>>>> } >>>> var >>>> photos = [], >>>> captions = [], >>>> len = library.length; >>>> >>>> photos.length = captions.length = len; >>>> >>>> for (var i = len; i--;) >>>> { >>>> var o = library[i]; >>>> photos[i] = o.img; >>>> captions[i] = o.caption; >>>> } >>> Yes, the start's a bit nicer (library length). I don't know if that >>> assignment to o will help though. You only saved two lookups. Not >>> worth worrying about it at this point. >> >> Benchmarks suggest it would be about 20% faster in TraceMonkey 1.9.1.6. >> > Setting the length will avoid step 10 in array [[Put]], so should be > fastest. IE versions may benefit even more from this. But, as Thomas noted, it will be set (for good) the first time as we are going backwards.
From: Garrett Smith on 13 Jan 2010 12:17 Tuxedo wrote: > Hi, > > I have an array with image source and caption object pairs, such as: > > var library = [{ img: 'img01.jpg', caption: 'Caption 1'}, > { img: 'img02.jpg', caption: 'Caption 2'}, > { img: 'img03.jpg', caption: 'Caption 3'}]; > > I would like to return copies of the above as if the contents had been > placed in two separate arrays, like: > > var photos = ['img01.jpg', 'img02.jpg', 'img03.jpg'] > var captions = ['Caption 1', 'Caption 2', 'Caption 3'] > > But obviously I'd like to avoid repeating code unecessarily in form of > duplicate typed out content as several arrays. Instead, I would like to > access separate arrays of photos and captions, derived from the library > array, as if they were two separate arrays in the first place, so that: ... > > alert(photos) would return: img01.jpg,img02.jpg,img03.jpg > alert(captions) would return: Caption 1,Caption 2,Caption 3 > > How can the contents be copied from the 'library' array into two separate > virtual arrays named 'photos' and 'captions' which can be accessed like > normal single level arrays? > Where supported, in JS 1.8 or in ES5, you can use Array.prototype.map[1]. Array.prototype.map creates a new array with the results of calling a provided function on every element in this array. That would look like: (function(){ var library = [{ img: 'img01.jpg', caption: 'Caption 1'}, { img: 'img02.jpg', caption: 'Caption 2'}, { img: 'img03.jpg', caption: 'Caption 3'}]; function filterByName(prop){ return function(element){ return element[prop]; }; } var imgArray = library.map(filterByName("img")); var captionArray = library.map(filterByName("caption")); })(); Where not supported, Array.prototype.map functionality can be added, as indicated on MDC page[1]. Writing your own loop would be fastest here. [1]https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map -- Garrett comp.lang.javascript FAQ: http://jibbering.com/faq/
From: Scott Sauyet on 13 Jan 2010 17:13
On Jan 13, 10:13 am, Thomas 'PointedEars' Lahn <PointedE...(a)web.de> wrote: >> Scott Sauyet wrote: >>> var photos = [], captions = []; >>> for (var i = 0, len = library.length; i < len; i++) { >>> photos.push(library[i]["img"]); >>> captions.push(library[i]["caption"]); >>> } > var > photos = [], > captions = [], > len = library.length; > > photos.length = captions.length = len; > > for (var i = len; i--;) > { > var o = library[i]; > photos[i] = o.img; > captions[i] = o.caption; > } Any of the suggestions will work, of course. The differences have to do with readability versus performance. Perhaps the most readable version would be something like this: var photos = []; var captions = []; for (var i = 0; i < library.length; i++) { var element = library[i]; photos.push(element.img); captions.push(element.caption); } For people used to C-style languages, that loop will feel quite familiar. My version added three minor changes: combining the initial declarations into one statement, hoisting the length field out of the loop, and removing the additional variable declaration inside the loop. The first is mainly an issue of style (and perhaps bandwidth). The second can be quite important for performance if the length is determined by calling a heavy-weight function (such as if the list were a dynamic collection of DOM nodes) but it probably has little effect with a simple array like this. I have no idea how the third change affects performance. What Thomas suggests optimizes by reversing the iteration order. I have heard that such a change often improves performance of JS loops, but I don't know any numbers. The main disadvantage for beginning programmers is that the loop is somewhat less readable, at least until you get used to the convention. It takes advantage of the fact that 0 in a test is read as false, whereas positive integers are read as true. One nice variation of this is this loop format: for (var i = library.length; i --> 0;) { // ... } This looks like "for i, starting at library.length, proceeding to 0, do something". It really looks as though the code contains an arrow ("-->"). In actuality this is the postfix decrement operator ("--") followed by a greater-than compare (">"), and it takes advantage of the fact that the comparison happens before the decrement. But it's very pretty. The OP will have to decide how to weight performance advantages against code clarity, but in order to help, does anyone have links to metrics on the different performance characteristics of loops in different browser environments? -- Scott |