From: Garrett Smith on
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
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
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
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
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