How to copy multi object array contents into single object arrays?

Discussion in 'Javascript' started by Tuxedo, Jan 13, 2010.

  1. Tuxedo

    Tuxedo Guest

    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?

    Many thanks,
    Tuxedo
     
    Tuxedo, Jan 13, 2010
    #1
    1. Advertising

  2. Tuxedo

    Scott Sauyet Guest

    Re: How to copy multi object array contents into single objectarrays?

    On Jan 13, 9:12 am, Tuxedo <> wrote:
    > 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']


    var photos = [], captions = [];
    for (var i = 0, len = library.length; i < len; i++) {
    photos.push(library["img"]);
    captions.push(library["caption"]);
    }

    -- Scott
     
    Scott Sauyet, Jan 13, 2010
    #2
    1. Advertising

  3. Tuxedo

    David Mark Guest

    Re: How to copy multi object array contents into single object arrays?

    Scott Sauyet wrote:
    > On Jan 13, 9:12 am, Tuxedo <> wrote:
    >> 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']

    >
    > var photos = [], captions = [];
    > for (var i = 0, len = library.length; i < len; i++) {
    > photos.push(library["img"]);
    > captions.push(library["caption"]);
    > }
    >


    var photos = [], captions = [];
    photos.length = captions.length = library.length;
    for (var i = 0, len = library.length; i--;) {
    photos = library["img"];
    captions = library["caption"];
    }
     
    David Mark, Jan 13, 2010
    #3
  4. Re: How to copy multi object array contents into single object arrays?

    David Mark wrote:

    > Scott Sauyet wrote:
    >> var photos = [], captions = [];
    >> for (var i = 0, len = library.length; i < len; i++) {
    >> photos.push(library["img"]);
    >> captions.push(library["caption"]);
    >> }

    >
    > var photos = [], captions = [];
    > photos.length = captions.length = library.length;
    > for (var i = 0, len = library.length; i--;) {


    No :)

    > photos = library["img"];
    > captions = library["caption"];
    > }


    var
    photos = [],
    captions = [],
    len = library.length;

    photos.length = captions.length = len;

    for (var i = len; i--;)
    {
    var o = library;
    photos = o.img;
    captions = o.caption;
    }


    PointedEars
    --
    var bugRiddenCrashPronePieceOfJunk = (
    navigator.userAgent.indexOf('MSIE 5') != -1
    && navigator.userAgent.indexOf('Mac') != -1
    ) // Plone, register_function.js:16
     
    Thomas 'PointedEars' Lahn, Jan 13, 2010
    #4
  5. Re: How to copy multi object array contents into single object arrays?

    Thomas 'PointedEars' Lahn wrote:

    > var
    > photos = [],
    > captions = [],
    > len = library.length;
    >
    > photos.length = captions.length = len;
    >
    > for (var i = len; i--;)
    > {
    > var o = library;
    > photos = o.img;
    > captions = o.caption;
    > }


    As we are iterating from end to start, does it even make sense to set the
    `length' property? For it will be set in the first iteration anyway.


    PointedEars
    --
    Danny Goodman's books are out of date and teach practices that are
    positively harmful for cross-browser scripting.
    -- Richard Cornford, cljs, <cife6q$253$1$> (2004)
     
    Thomas 'PointedEars' Lahn, Jan 13, 2010
    #5
  6. Tuxedo

    David Mark Guest

    Re: How to copy multi object array contents into single objectarrays?

    On Jan 13, 10:13 am, 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["img"]);
    > >> captions.push(library["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?

    >
    > > photos = library["img"];
    > > captions = library["caption"];
    > > }

    >
    > var
    > photos = [],
    > captions = [],
    > len = library.length;
    >
    > photos.length = captions.length = len;
    >
    > for (var i = len; i--;)
    > {
    > var o = library;
    > photos = o.img;
    > captions = 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. I just didn't care for the
    original.
     
    David Mark, Jan 13, 2010
    #6
  7. Tuxedo

    David Mark Guest

    Re: How to copy multi object array contents into single objectarrays?

    On Jan 13, 10:17 am, Thomas 'PointedEars' Lahn <>
    wrote:
    > Thomas 'PointedEars' Lahn wrote:
    > > var
    > > photos = [],
    > > captions = [],
    > > len = library.length;

    >
    > > photos.length = captions.length = len;

    >
    > > for (var i = len; i--;)
    > > {
    > > var o = library;
    > > photos = o.img;
    > > captions = o.caption;
    > > }

    >
    > As we are iterating from end to start, does it even make sense to set the
    > `length' property? For it will be set in the first iteration anyway.
    >


    No. I originally had it going forward rather than reverse. Best to
    drop that opening bit entirely when going in reverse. I should have
    re-read it. Long night.
     
    David Mark, Jan 13, 2010
    #7
  8. 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["img"]);
    >> >> captions.push(library["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 = library["img"];
    >> > captions = library["caption"];
    >> > }

    >>
    >> var
    >> photos = [],
    >> captions = [],
    >> len = library.length;
    >>
    >> photos.length = captions.length = len;
    >>
    >> for (var i = len; i--;)
    >> {
    >> var o = library;
    >> photos = o.img;
    >> captions = 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.


    PointedEars
    --
    Prototype.js was written by people who don't know javascript for people
    who don't know javascript. People who don't know javascript are not
    the best source of advice on designing systems that use javascript.
    -- Richard Cornford, cljs, <f806at$ail$1$>
     
    Thomas 'PointedEars' Lahn, Jan 13, 2010
    #8
  9. 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["img"]);
    >>>>> captions.push(library["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 = library["img"];
    >>>> captions = library["caption"];
    >>>> }
    >>> var
    >>> photos = [],
    >>> captions = [],
    >>> len = library.length;
    >>>
    >>> photos.length = captions.length = len;
    >>>
    >>> for (var i = len; i--;)
    >>> {
    >>> var o = library;
    >>> photos = o.img;
    >>> captions = 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/
     
    Garrett Smith, Jan 13, 2010
    #9
  10. Tuxedo

    David Mark Guest

    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["img"]);
    >>>>>> captions.push(library["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 = library["img"];
    >>>>> captions = library["caption"];
    >>>>> }
    >>>> var
    >>>> photos = [],
    >>>> captions = [],
    >>>> len = library.length;
    >>>>
    >>>> photos.length = captions.length = len;
    >>>>
    >>>> for (var i = len; i--;)
    >>>> {
    >>>> var o = library;
    >>>> photos = o.img;
    >>>> captions = 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.
     
    David Mark, Jan 13, 2010
    #10
  11. Tuxedo

    David Mark Guest

    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["img"]);
    >>>>>> captions.push(library["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 = library["img"];
    >>>>> captions = library["caption"];
    >>>>> }
    >>>> var
    >>>> photos = [],
    >>>> captions = [],
    >>>> len = library.length;
    >>>>
    >>>> photos.length = captions.length = len;
    >>>>
    >>>> for (var i = len; i--;)
    >>>> {
    >>>> var o = library;
    >>>> photos = o.img;
    >>>> captions = 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.
     
    David Mark, Jan 13, 2010
    #11
  12. 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/
     
    Garrett Smith, Jan 13, 2010
    #12
  13. Tuxedo

    Scott Sauyet Guest

    Re: How to copy multi object array contents into single objectarrays?

    On Jan 13, 10:13 am, Thomas 'PointedEars' Lahn <>
    wrote:
    >> Scott Sauyet wrote:
    >>>     var photos = [], captions = [];
    >>>     for (var i = 0, len = library.length; i < len; i++) {
    >>>         photos.push(library["img"]);
    >>>         captions.push(library["caption"]);
    >>>     }


    >   var
    >     photos = [],
    >     captions = [],
    >     len = library.length;
    >
    >    photos.length = captions.length = len;
    >
    >    for (var i = len; i--;)
    >    {
    >      var o = library;
    >      photos = o.img;
    >      captions = 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;
    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
     
    Scott Sauyet, Jan 13, 2010
    #13
  14. Scott Sauyet wrote:

    > Thomas 'PointedEars' Lahn wrote:
    >>> Scott Sauyet wrote:
    >>>> var photos = [], captions = [];
    >>>> for (var i = 0, len = library.length; i < len; i++) {
    >>>> photos.push(library["img"]);
    >>>> captions.push(library["caption"]);
    >>>> }

    >>
    >> var
    >> photos = [],
    >> captions = [],
    >> len = library.length;
    >>
    >> photos.length = captions.length = len;
    >>
    >> for (var i = len; i--;)
    >> {
    >> var o = library;
    >> photos = o.img;
    >> captions = o.caption;
    >> }

    >
    > Any of the suggestions will work, of course.


    Alas, not all, as I have pointed out.

    > 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;
    > photos.push(element.img);
    > captions.push(element.caption);
    > }
    >
    > For people used to C-style languages, that loop will feel quite
    > familiar.


    You don't know what you are talking about. First of all, for all intents
    and purposes, ECMAScript is a C-style language. (If you have eyes to see
    you can observed the similarities.)

    (Therefore,) the backwards-counting loop will be familiar to "people used
    to C-style languages", and it will also be a lot more efficient than the
    one above. After all there is no boolean type in C before C99, so you
    would use `int' (and guess what, C's `for' statement works the same as in
    ECMAScript save the implicit conversion!), and in C99 you would use
    `(_Bool) i--' for maximum efficiency.

    The ascending order and the unnecessary push() calls will decrease
    efficiency considerably, and the push() call will decrease compatibility,
    too (JScript 5.0 does not have it).

    > My version added three minor changes: combining the initial
    > declarations into one statement, hoisting the length field out of the


    There is no field, `length' is a property.

    > 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.


    It affects it considerably, as variable instantiation only happens once
    before execution, and identifiers are _not_ block-scoped -- don't you know
    *anything*?

    As a result, removing the variable declaration and initialization, rather
    unsurprisingly, *decreases* performance as the property lookup is repeated.
    Make benchmarks (or take more care when reading, and observe the results
    that I have posted already).

    > 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.


    Make benchmarks then, and you will see that the simple post-decrement
    increases efficiency considerably as well (else the pattern would not have
    prevailed, would it?). We have been over this ad nauseam before.

    > 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.


    Do you get a kick out of explaining the obvious even though nobody has
    asked a question? And you are being imprecise after all: *All* numeric
    values *except* 0 (+0 and -0, but these are only Specification mechanisms)
    and NaN type-convert to `true'. We have discussed this numerous times as
    well.

    > 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.


    As in the more simple and more efficient i-- ...

    > But it's very pretty.


    Pretty according to whose standards? It could create misconceptions with
    newcomers about a limit-type `-->' operator, and it is even less readable
    or obvious than the versions you were incompetently whining about.

    > 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?


    The browser does not matter (the ECMAScript implementation does), and this
    discussion has been performed a hundred times or so already. So have
    results been posted. Much you have to learn.


    Score adjusted

    PointedEars
    --
    Danny Goodman's books are out of date and teach practices that are
    positively harmful for cross-browser scripting.
    -- Richard Cornford, cljs, <cife6q$253$1$> (2004)
     
    Thomas 'PointedEars' Lahn, Jan 14, 2010
    #14
  15. Tuxedo

    Tuxedo Guest

    Thanks to all for posting the various code examples, it more than solved my
    small multi to single array items conversion problem!

    Tuxedo
     
    Tuxedo, Jan 14, 2010
    #15
  16. Tuxedo

    Scott Sauyet Guest

    Re: How to copy multi object array contents into single objectarrays?

    On Jan 13, 7:18 pm, Thomas 'PointedEars' Lahn <>
    wrote:
    > Scott Sauyet wrote:
    >> 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;
    >> photos.push(element.img);
    >> captions.push(element.caption);
    >> }

    >
    >> For people used to C-style languages, that loop will feel quite
    >> familiar.

    >
    > You don't know what you are talking about. First of all, for all intents
    > and purposes, ECMAScript is a C-style language. (If you have eyes to see
    > you can observed the similarities.)


    I'm sure that often I don't, but in fact here I do know what I'm
    talking about. Javascript is syntactically in the family of C-style
    languages most recognizable for blocks delimited with curly braces.
    Just about any programmer who has programmed with a member of this
    family of languages will recognize this syntax:

    for (i = 0; i < bound; i++) {
    // Do something.
    }

    They not only recognize it, but have themselves have coded with it.
    The general form has been described [1] as

    for (initialization; continuation condition; incrementing expr)
    {
    statement(s)
    }

    This is of course inaccurate, because the last expression does not
    *have* to increment. It can decrement, it can do some strange
    combination, or it can be skipped altogether. But the incrementing
    version is the form with which programmers are most familiar.

    > (Therefore,) the backwards-counting loop will be familiar to "people used
    > to C-style languages",



    Many, probably most, will recognize this easily enough:

    for (i = bound; i > 0; i--) {
    // Do something.
    }

    But this is a less commonly used, and less familiar, variation. The
    following one though, is seen significantly less often:

    for (i = bound; i--;) {
    // Do something.
    }

    It won't work in languages which do not read a zero as false (Java),
    and it might be frowned upon on languages which do so, but discourage
    it (PHP?). I would not suggest it to a beginner unless it was to
    clear up some performance problem.

    The point, though, is that the OP was posting a problem that could be
    solved easily by someone with only a little Javascript experience. It
    might be a bad guess, but I did guess that the OP was a JS beginner,
    and gave the simplest answer I could think of that could work (except
    that I didn't think to remove what's become standard for me in
    hoisting the loop bound.)


    > and it will also be a lot more efficient than the
    > one above. [ ... ]


    I did say that I had heard that descending loops in JS were more
    efficient than ascending ones, and asked if there was documentation
    for that. I'm sorry, but your assertion is not enough proof for me.
    Do you know of any decent references?


    > The ascending order and the unnecessary push() calls will decrease
    > efficiency considerably, and the push() call will decrease compatibility,
    > too (JScript 5.0 does not have it).


    I don't know about the OP, but I tend to worry little about JScript
    5.0. As to the efficiency claims, do you have any documentation?


    >> My version added three minor changes: combining the initial
    >> declarations into one statement, hoisting the length field out of the

    >
    > There is no field, `length' is a property.


    True. Pedantic, but true.


    >> 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.

    >
    > It affects it considerably, as variable instantiation only happens once
    > before execution, and identifiers are _not_ block-scoped


    Yes, they are function-scoped in JS.

    So you're saying that this:

    for (var i = 0; i < library.length; i++) {
    var element = library;
    photos.push(element.img);
    captions.push(element.caption);
    }

    is considerably more efficient than this:

    for (var i = 0; i < library.length; i++) {
    photos.push(library.img);
    captions.push(library.caption);
    }

    I don't know the relative costs of variable assignment versus array
    look-up. Do you have any references on this? I count an additional
    assignment in the first and one fewer look-up. Does that offer a
    considerable performance gain?


    > don't you know *anything*?


    Yes. I do.


    > As a result, removing the variable declaration and initialization, rather
    > unsurprisingly, *decreases* performance as the property lookup is repeated.
    > Make benchmarks (or take more care when reading, and observe the results
    > that I have posted already).


    I see differences in integer array look-ups, not arbitrary property
    look-ups. I don't know if ES implementations have any optimizations
    for dense arrays over arbitrary property look-ups.

    As to benchmarks, perhaps I will try some. But if you have
    references, would you please share them? Still, you are the one
    making the claim. Have you any benchmarks of your own to share?


    >> 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.

    >
    > Make benchmarks then, and you will see that the simple post-decrement
    > increases efficiency considerably as well (else the pattern would not have
    > prevailed, would it?). We have been over this ad nauseam before.


    Funny, you're often the one berating others for not understanding
    USENET. Having been over a subject ad nauseam, the group is best off
    pointing new users to FAQ entries or other resources. All you've done
    is make assertions.


    >> 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.

    >
    > Do you get a kick out of explaining the obvious even though nobody has
    > asked a question?


    Again, the OP asked a relatively easy question, and has received
    several competing solutions. If the OP knew all that, don't you think
    it likely she or he would have been able to solve the problem without
    asking in this group?


    > And you are being imprecise after all: *All* numeric
    > values *except* 0 (+0 and -0, but these are only Specification mechanisms)
    > and NaN type-convert to `true'. We have discussed this numerous times as
    > well.


    No, I was being quite precise. The construct under discussion does
    not take advantage of the fact that 2.718281828 or -pi are interpreted
    as true, only that the positive integers are.

    But thank you for pointing this out, as it brings to mind another
    potential pitfall of this technique: if the body of your loop
    decrements the loop variable, you might transform working code into a
    nearly-endless loop. Of course this is a sign of bad code, but it's
    more likely to happen with an equality condition ("i") than an
    inequality ("i < bound").


    >> One nice variation of this is this loop format:

    >
    >> for (var i = library.length; i --> 0;) {
    >> // ...
    >> }

    > [ ... ]
    >> But it's very pretty.

    >
    > Pretty according to whose standards?


    The eye of the beholder, of course. Who else would you appoint the
    arbiter of code beauty?

    But I personally find it very appealing.


    > It could create misconceptions with
    > newcomers about a limit-type `-->' operator, and it is even less readable
    > or obvious than the versions you were incompetently whining about.


    Suddenly you're worried about newcomers? :)

    My previous post was clearly not aimed at those who know Javascript
    well, just an attempt to help the OP. But I'm not sure that your two
    clauses above really work together well. If it creates misconceptions
    about a non-existent operator, it's only *because* it is more readable
    to the newcomer.

    Still, I take offense at the notion that my whining was incompetent.
    It clearly grated on you, so it seems to be very competent
    whining. :)


    >> 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?

    >
    > The browser does not matter (the ECMAScript implementation does),


    Overly pedantic again, but I'll certainly concede the point.


    > and this discussion has been performed a hundred times or so
    > already. So have results been posted.


    Do you happen to have references?


    > Much you have to learn.


    Yes I do. I'm just hoping to find some competent instructors.


    > Score adjusted


    So it's what now? 40 - love, my serve again?


    -- Scott
    ____________________
    [1] http://en.wikipedia.org/wiki/Curly_bracket_programming_language#Loops
     
    Scott Sauyet, Jan 14, 2010
    #16
  17. Tuxedo

    Scott Sauyet Guest

    Re: How to copy multi object array contents into single objectarrays?

    On Jan 14, 11:41 am, Scott Sauyet <> wrote:
    > As to benchmarks, perhaps I will try some.


    Ok, I tried. I don't have much experience at JS benchmarks, so there
    may be major flaws in them. I'd appreciate it if someone could point
    out improvements.

    I've posted some tests here:

    http://scott.sauyet.com/Javascript/Test/LoopTimer/1/test/

    These tests run two of the code samples discussed earlier [1, 2]
    multiple times. I try them with initial arrays of length 10, 100,
    1000, and 10000. I run them, respectively, 100000, 10000, 1000, and
    100 times, so in each case the number of iterations of the main body
    of the function will happen one million times. (This should lead to
    slightly higher efficiency with larger arrays, as the outer loop has
    to run fewer times, but I suspect that that's only noise in the
    results.) To run this in IE, I could only run one test at a time or
    the browser would alert me of long-running scripts and my running
    times were compromised.

    In any case, I report the number of iterations of the tested algorithm
    that run per millisecond.

    I collected the results at

    http://scott.sauyet.com/Javascript/Test/LoopTimer/1/

    But I've done something screwy to IE on the page trying to be clever.
    If anyone can tell me why the generated links are not working properly
    in IE, I would love to know. In other browsers, you can see the
    results, run one of the predefined tests, or choose to run either
    algorithm in your browser, supplying the size of the array and the
    number of iterations to run.

    I tested on the browsers I have on my work machine:

    Chrome 3.0.195.27
    FF 3.5.7
    IE 8
    Opera 9.64
    Safari 4.0.3

    All running on Windows XP on a fairly powerful machine.

    The results definitely say that the backward looping algorithm
    supplied by Thomas is generally more efficient than the forward one I
    gave. But there is some murkiness. First of all, the values reported
    as this is run in different browsers (and specifically in their
    ECMAScript implementations, for the pedantic among you) vary hugely.
    They can differ by a factor of 50 or more.

    In Opera the backward looping was faster at all array sizes, by an
    approximate factor of 3. In Safari it was faster by a factor of 5.
    In IE, it was faster, but at a factor that decreased as the array size
    increased, down to about 1.21 for a 10000-element array. In Firefox
    and Chrome it was more complicated. For array sizes of 10, 100, and
    1000 in Chrome, the backward was faster than forward by factors
    approximately 1.5 - 2.5. But for 10000 elements, forward was faster
    by a factor of about 1.25; I checked at 100000 elements too, and
    forward was faster by a factor of about 1.5. In Firefox, backwards
    was faster than forwards for 10 and 100 elements, by a factor of 1.5
    and 2, respectively, but for 1000, forward was faster than backward by
    a factor of 17, and at 10000, forward was faster by a factor of 27.
    It's not that forward improved at higher array sizes in FF but that
    backwards slowed way down.

    I did try reversing the order of the tests to see if garbage
    collection had anything to do with this, but it make no substantive
    difference.

    The conclusion I can draw from this is that backward is generally a
    better bet, but that might be reversed for higher array sizes, at
    least in FF and Chrome.

    So, has anyone got suggestions for improving these tests? Can someone
    tell me what's wrong in IE in my results page?

    -- Scott Sauyet
    ____________________
    [1] http://groups.google.com/group/comp.lang.javascript/msg/73c40b2b284d970a
    [2] http://groups.google.com/group/comp.lang.javascript/msg/6c56a2bac08daaa4
     
    Scott Sauyet, Jan 14, 2010
    #17
  18. Tuxedo

    Jorge Guest

    Re: How to copy multi object array contents into single objectarrays?

    On Jan 14, 7:17 pm, Scott Sauyet <> wrote:
    > (...)
    > So, has anyone got suggestions for improving these tests?
    > (...)


    Yes, :)
    http://jorgechamorro.com/cljs/093/

    BTW, It's not faster i-- than i++.
    Cheers,
    --
    Jorge.
     
    Jorge, Jan 14, 2010
    #18
  19. Tuxedo

    Scott Sauyet Guest

    Re: How to copy multi object array contents into single objectarrays?

    On Jan 14, 2:53 pm, Jake Jarvis <> wrote:
    > Scott Sauyet wrote:
    >> I collected the results at
    >>    http://scott.sauyet.com/Javascript/Test/LoopTimer/1/
    >> But I've done something screwy to IE on the page trying to be clever.
    >> If anyone can tell me why the generated links are not working properly
    >> in IE, I would love to know.


    > line 120:
    >
    > | var size = parseInt(cells.textContent, 10) || 1,
    >                                ^^^^^^^^^^^
    > No such thing in mshtml


    D'OH. Self-administered dope-slap! I guess that's what I guess for
    throwing things together.

    Thank you very much.

    -- Scott
     
    Scott Sauyet, Jan 14, 2010
    #19
  20. Tuxedo

    Scott Sauyet Guest

    Re: How to copy multi object array contents into single objectarrays?

    On Jan 14, 3:23 pm, Scott Sauyet <> wrote:
    > On Jan 14, 2:53 pm, Jake Jarvis <> wrote:
    >
    > > Scott Sauyet wrote:
    > >> I collected the results at
    > >>    http://scott.sauyet.com/Javascript/Test/LoopTimer/1/
    > >> But I've done something screwy to IE on the page trying to be clever.
    > >> If anyone can tell me why the generated links are not working properly
    > >> in IE, I would love to know.

    > > line 120:

    >
    > > | var size = parseInt(cells.textContent, 10) || 1,
    > >                                ^^^^^^^^^^^
    > > No such thing in mshtml

    >
    > D'OH.  Self-administered dope-slap!  I guess that's what I guess for
    > throwing things together.


    Updated version:

    http://scott.sauyet.com/Javascript/Test/LoopTimer/2/

    Thanks again,

    -- Scott
     
    Scott Sauyet, Jan 14, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    6
    Views:
    30,447
    Diplomat
    Jan 12, 2011
  2. Venkat
    Replies:
    4
    Views:
    1,005
    Venkat
    Dec 5, 2003
  3. Alex
    Replies:
    2
    Views:
    1,273
  4. Philipp
    Replies:
    21
    Views:
    1,172
    Philipp
    Jan 20, 2009
  5. Wirianto Djunaidi
    Replies:
    2
    Views:
    222
    Wirianto Djunaidi
    Apr 29, 2008
Loading...

Share This Page