How do you change all elements in a Collection at the same time?

Discussion in 'Java' started by phillip.s.powell@gmail.com, Jan 12, 2007.

  1. Guest

    In my native language, PHP, we have a function called array_walk()
    http://www.php.net/manual/en/function.array-walk.php

    That will walk through an array and perform change on every element in
    the array.

    I've studied the Collections within Java so far and this seems like the
    right way to do it (Collections.replaceAll(List list, Object oldVal,
    Object newVal)):
    http://java.sun.com/j2se/1.4.2/docs...util.List, java.lang.Object, java.lang.Object)

    But looking at the API does not tell me how to do a function-based
    "array_walk" like we can so easily do in PHP:

    <?
    $array = array(1, 2, 3, 4, 5);
    @array_walk($array, create_function('&$a', 'return ($a + 1);')); //
    WILL RETURN (2, 3, 4, 5, 6)
    ?>

    So how do I do this in Java?

    Thanx
    Phil
     
    , Jan 12, 2007
    #1
    1. Advertising

  2. Guest

    Paul Hamaker wrote:
    > As of Java5 :
    > for ( SomeClass c : somecoll )
    > { //do something with (each) c in somecoll, like :
    > c.change(somearg);


    But what if you won't know what "change()" will be? That is, I could be
    doing any kind of uniform change to the collection; I could be adding
    by 1, rearranging strings, converting Objects, literally anything at
    all (except removing them)

    Here is where I can't find the Java equivalent of "eval()", something
    in PHP that's normal to me.

    Phil

    > }
    > --
    > http://javalessons.com Paul Hamaker, SEMM
    > Teaching ICT since 1987
     
    , Jan 12, 2007
    #2
    1. Advertising

  3. Tom Hawtin Guest

    wrote:
    >
    > That will walk through an array and perform change on every element in
    > the array.


    > $array = array(1, 2, 3, 4, 5);
    > @array_walk($array, create_function('&$a', 'return ($a + 1);')); //
    > WILL RETURN (2, 3, 4, 5, 6)


    For a one off, you could write it explicitly as:

    List<Integer> values = Arrays.asList(new Integer[] {
    1, 2, 3, 4, 5
    });
    for (
    ListIterator<Integer> iter = values.listIterator();
    Integer value = iter.next();
    ) {
    iter.set(value + 1);
    }
    System.out.println(values);

    To abstract the 'array walking' takes a bit more work:

    public interface Transform<T> {
    T transform(T value);
    }
    ....
    public <T> static void transform(
    List<T> values, Transform<T> transform
    ) {
    for (
    ListIterator<T> iter = values.listIterator();
    T value = iter.next();
    ) {
    iter.set(transform.transform(value));
    }
    }
    ....
    List<Integer> values = Arrays.asList(new Integer[] {
    1, 2, 3, 4, 5
    });
    transform(values, new Transform<Integer>() {
    public Integer transform(Integer value) {
    return value+1;
    }
    });
    System.out.println(values);

    I have used List instead of Collection, because Collection doesn't
    provide a ListIterator and it's not an entirely sensible operation to
    perform on a set anyway.


    As you can see, abstracting loops is not a particularly natural thing to
    do in Java. After splitting the method, my example is only one line
    shorter and indents three levels instead of one. The inner class can
    only reference final variables of the enclosing method. So it isn't done
    very often in Java, at the moment.

    There are various proposals to make things simpler in Java 7. These will
    allow something like:

    // BGGA
    transform(values) {
    Integer value => value+1
    }

    transform(values, { Integer value => value+1 });

    // CICE (possibly without the <Integer>).
    transform(values, Transform<Integer>(Integer value) {
    return value+1;
    });

    // My favourite:
    transform(values, new()(Integer value) {
    return value+1;
    });

    Tom Hawtin
     
    Tom Hawtin, Jan 12, 2007
    #3
  4. Rogan Dawes Guest

    wrote:
    > Paul Hamaker wrote:
    >> As of Java5 :
    >> for ( SomeClass c : somecoll )
    >> { //do something with (each) c in somecoll, like :
    >> c.change(somearg);

    >
    > But what if you won't know what "change()" will be? That is, I could be
    > doing any kind of uniform change to the collection; I could be adding
    > by 1, rearranging strings, converting Objects, literally anything at
    > all (except removing them)
    >
    > Here is where I can't find the Java equivalent of "eval()", something
    > in PHP that's normal to me.
    >
    > Phil
    >


    Java is not an interpreted language. Hence it does not have "eval",
    since the classes and methods may not actually be present on the classpath.

    If you REALLY need "eval" functionality, and cannot achieve what you
    need using sub-classes and/or interfaces, you may want to take a look at
    BeanShell, which is an interpreted version of Java.

    Regards,

    Rogan
     
    Rogan Dawes, Jan 12, 2007
    #4
  5. Guest

    Rogan Dawes wrote:
    > wrote:
    > > Paul Hamaker wrote:
    > >> As of Java5 :
    > >> for ( SomeClass c : somecoll )
    > >> { //do something with (each) c in somecoll, like :
    > >> c.change(somearg);

    > >
    > > But what if you won't know what "change()" will be? That is, I could be
    > > doing any kind of uniform change to the collection; I could be adding
    > > by 1, rearranging strings, converting Objects, literally anything at
    > > all (except removing them)
    > >
    > > Here is where I can't find the Java equivalent of "eval()", something
    > > in PHP that's normal to me.
    > >
    > > Phil
    > >

    >
    > Java is not an interpreted language. Hence it does not have "eval",
    > since the classes and methods may not actually be present on the classpath.
    >
    > If you REALLY need "eval" functionality, and cannot achieve what you
    > need using sub-classes and/or interfaces, you may want to take a look at
    > BeanShell, which is an interpreted version of Java.


    Thanx I'll look into it. I don't however see how BeanShell will do
    what I need to do within classes for a Java application to do what PHP
    can do with eval() and array_walk() more easily. :(

    Phil

    >
    > Regards,
    >
    > Rogan
     
    , Jan 12, 2007
    #5
  6. wrote:
    > Paul Hamaker wrote:
    >> As of Java5 :
    >> for ( SomeClass c : somecoll )
    >> { //do something with (each) c in somecoll, like :
    >> c.change(somearg);

    >
    > But what if you won't know what "change()" will be? That is, I could be
    > doing any kind of uniform change to the collection; I could be adding
    > by 1, rearranging strings, converting Objects, literally anything at
    > all (except removing them)


    The suggested code is not an implementation of array_walk, but a
    replacement for it. Use it at the point in the code where you decide to
    do a specific thing to every element of a collection. Replace
    c.change(somearg) with whatever operation, or combination of operations,
    you want.

    >
    > Here is where I can't find the Java equivalent of "eval()", something
    > in PHP that's normal to me.


    If you consider "eval()" to be essential for whatever you are doing, you
    should use an interpreted language, such as PHP.

    Patricia
     
    Patricia Shanahan, Jan 12, 2007
    #6
  7. Mark Rafn Guest

    >Paul Hamaker wrote:
    >> As of Java5 :
    >> for ( SomeClass c : somecoll )
    >> { //do something with (each) c in somecoll, like :
    >> c.change(somearg);


    <> wrote:
    >But what if you won't know what "change()" will be? That is, I could be
    >doing any kind of uniform change to the collection; I could be adding
    >by 1, rearranging strings, converting Objects, literally anything at
    >all (except removing them)


    Define an interface like
    public interface SomeClassProcessor { void process(SomeClass c); }
    and have the caller (whoever it is that DOES know what to do with each
    element) pass you an instance of SomeClassProcessor. Call process(c) on each
    element.

    >Here is where I can't find the Java equivalent of "eval()", something
    >in PHP that's normal to me.


    eval() is misspelled. Change the a to an i. It completely breaks any sort of
    compile-time analysis, and cannot be optimized in any reasonable way.
    --
    Mark Rafn <http://www.dagon.net/>
     
    Mark Rafn, Jan 12, 2007
    #7
  8. Daniel Pitts Guest

    wrote:
    > In my native language, PHP, we have a function called array_walk()
    > http://www.php.net/manual/en/function.array-walk.php
    >
    > That will walk through an array and perform change on every element in
    > the array.
    >
    > I've studied the Collections within Java so far and this seems like the
    > right way to do it (Collections.replaceAll(List list, Object oldVal,
    > Object newVal)):
    > http://java.sun.com/j2se/1.4.2/docs...util.List, java.lang.Object, java.lang.Object)
    >
    > But looking at the API does not tell me how to do a function-based
    > "array_walk" like we can so easily do in PHP:
    >
    > <?
    > $array = array(1, 2, 3, 4, 5);
    > @array_walk($array, create_function('&$a', 'return ($a + 1);')); //
    > WILL RETURN (2, 3, 4, 5, 6)
    > ?>
    >
    > So how do I do this in Java?
    >
    > Thanx
    > Phil

    Java doesn't exactly have closures, so its hard to do stuff like what
    your asking.. However, what you really want is:

    Replacing "doChange" with whatever is appropriate.

    You COULD make a utility class that does this for you:

    public interface Transformer {
    Object transform(Object o);
    }

    public class ListWalker {
    public static void walk(List myList, Transformer transformer) {
    ListIterator iterator = myList.listIterator();
    while (iterator.hasNext()) {
    iterator.set( transformer.transform(iterator.next()) );
    }
    }


    Now you can call:
    ListWalker.walk(myList, new Transformer() {
    public Object transform(Object o) {
    return new Integer(((Integer)o).intValue() + 1);
    }
    });

    Ick... Did I just write that?
    Well, you can't do little "tricks" with Java like you can in PHP, but
    don't worry about that too much.
     
    Daniel Pitts, Jan 13, 2007
    #8
  9. Eric Sosman Guest

    wrote:
    > Paul Hamaker wrote:
    >> As of Java5 :
    >> for ( SomeClass c : somecoll )
    >> { //do something with (each) c in somecoll, like :
    >> c.change(somearg);

    >
    > But what if you won't know what "change()" will be? [...]


    Then you don't know whether the "change" will preserve
    the collection's invariants. Imagine traversing a HashSet
    and applying a transformation that changed the hashCodes(),
    or a TreeSet() and changing the outcome of compareTo() ...

    Unrestricted change on a structured collection is not
    a Good Thing. If you want mapcar, you know where to find it.

    --
    Eric Sosman
    lid
     
    Eric Sosman, Jan 13, 2007
    #9
  10. Daniel Pitts wrote:
    > wrote:
    >> In my native language, PHP, we have a function called array_walk()
    >> That will walk through an array and perform change on every element in
    >> the array.
    >> <?
    >> $array = array(1, 2, 3, 4, 5);
    >> @array_walk($array, create_function('&$a', 'return ($a + 1);'));
    >> // WILL RETURN (2, 3, 4, 5, 6)
    >> ?>
    >>
    >> So how do I do this in Java?

    >
    > public interface Transformer {
    > Object transform(Object o);
    > }
    >
    > Now you can call:
    > ListWalker.walk(myList, new Transformer() {
    > public Object transform(Object o) {
    > return new Integer(((Integer)o).intValue() + 1);
    > }
    > });
    >
    > Ick... Did I just write that?


    It might be less icky using generics?

    interface Transformer<T> {
    T transform(T o);
    }

    ListWalker.walk(myList, new Transformer<Integer>() {
    public Integer transform(Integer i) { return i+1; }
    });
     
    RedGrittyBrick, Jan 13, 2007
    #10
  11. Lew Guest

    As so many on this thread have pointed out, Java can do what closures do, you
    just have to think in terms of object-orientation and polymorphism instead of
    interpreted, loosey-goosey self-rewriting code.

    Many have argued for closures in Java. I am against them for the moment, since
    there are already idioms that accomplish the same thing without the conceptual
    mindtwist. Once again, that would be polymorphism, possibly with inner or
    anonymous classes, combined with generics to provide compile-time safety.

    Java is a professional language, not a script-kiddie hack language. Things
    like program invariants, compile-time safety and maintainability carry weight
    here.

    - Lew
     
    Lew, Jan 13, 2007
    #11
  12. Lew wrote:
    > As so many on this thread have pointed out, Java can do what closures
    > do, you just have to think in terms of object-orientation and
    > polymorphism instead of interpreted, loosey-goosey self-rewriting code.
    >
    > Many have argued for closures in Java. I am against them for the moment,
    > since there are already idioms that accomplish the same thing without
    > the conceptual mindtwist. Once again, that would be polymorphism,
    > possibly with inner or anonymous classes, combined with generics to
    > provide compile-time safety.
    >
    > Java is a professional language, not a script-kiddie hack language.
    > Things like program invariants, compile-time safety and maintainability
    > carry weight here.


    I do not think it is fair to call closures a "script-kiddie
    hack language" feature.

    It is a language feature with some merits.

    Arne

    PS: I am also against adding closures to Java, but that
    is strictly to keep the size of the Java language
    down.
     
    =?ISO-8859-1?Q?Arne_Vajh=F8j?=, Jan 14, 2007
    #12
  13. Lew Guest

    (followup set to clj.programmer, as we proceed into a little more theoretical
    domain.)

    Arne Vajhøj wrote:
    > I do not think it is fair to call closures a "script-kiddie
    > hack language" feature.
    >
    > It is a language feature with some merits.


    You are right. However, when something like "eval" (or "evil", per Mark Rafn)
    combines with dynamic typing and a few other things that interpreted languages
    sport, you start to see some tangled code.

    Anyhow, my invective aside, you can accomplish the same effect, more or less,
    as closures using polymorphism over an interface, as suggested by Tom Hawtin
    for example. I believe the formal term is a "functor" class.

    - Lew
     
    Lew, Jan 14, 2007
    #13
  14. Lew wrote:
    > Arne Vajhøj wrote:
    >> I do not think it is fair to call closures a "script-kiddie
    >> hack language" feature.
    >>
    >> It is a language feature with some merits.


    > Anyhow, my invective aside, you can accomplish the same effect, more or
    > less, as closures using polymorphism over an interface, as suggested by
    > Tom Hawtin for example. I believe the formal term is a "functor" class.


    You can accomplish the same effect programming in assembler.

    Just because something can be done without X does not imply
    that X is not a good idea.

    It is a balance between how much easier some things are
    with X compared to the added complexity in language
    and implementations.

    Arne
     
    =?ISO-8859-1?Q?Arne_Vajh=F8j?=, Jan 14, 2007
    #14
  15. Guest

    Lew wrote:
    > (followup set to clj.programmer, as we proceed into a little more theoretical
    > domain.)
    >
    > Arne Vajhøj wrote:
    > > I do not think it is fair to call closures a "script-kiddie
    > > hack language" feature.
    > >
    > > It is a language feature with some merits.

    >
    > You are right. However, when something like "eval" (or "evil", per Mark Rafn)
    > combines with dynamic typing and a few other things that interpreted languages
    > sport, you start to see some tangled code.
    >
    > Anyhow, my invective aside, you can accomplish the same effect, more or less,
    > as closures using polymorphism over an interface, as suggested by Tom Hawtin
    > for example. I believe the formal term is a "functor" class.
    >
    > - Lew


    Speaking on behalf of the "kiddie script" writers, everything you said
    sailed over my head like a satellite. I have no clue what you're
    talking about, and I happen to love eval() because it makes me write
    one line of code instead of hundreds of lines of unmanageable code
    every time. Can't see the entanglement, dude.

    I don't understand quite how the code that Tom wrote works, simply
    because I don't understand the code Tom works period, but I'll keep
    looking into it though

    Phil
     
    , Jan 14, 2007
    #15
  16. Guest

    Eric Sosman wrote:
    > wrote:
    > > Paul Hamaker wrote:
    > >> As of Java5 :
    > >> for ( SomeClass c : somecoll )
    > >> { //do something with (each) c in somecoll, like :
    > >> c.change(somearg);

    > >
    > > But what if you won't know what "change()" will be? [...]

    >
    > Then you don't know whether the "change" will preserve
    > the collection's invariants. Imagine traversing a HashSet
    > and applying a transformation that changed the hashCodes(),
    > or a TreeSet() and changing the outcome of compareTo() ...
    >
    > Unrestricted change on a structured collection is not
    > a Good Thing. If you want mapcar, you know where to find it.


    But what does a Lisp function have to do with Java?

    >
    > --
    > Eric Sosman
    > lid
     
    , Jan 14, 2007
    #16
  17. Kai Schwebke Guest

    schrieb:
    > <?
    > $array = array(1, 2, 3, 4, 5);
    > @array_walk($array, create_function('&$a', 'return ($a + 1);')); //
    > WILL RETURN (2, 3, 4, 5, 6)
    > ?>
    >
    > So how do I do this in Java?


    As some have already pointed out this could be achieved
    (quite verbose) using a callback-like anonymous class
    implementing some interface.

    Another option would be heading towards Groovy, a dynamic
    language which runs on and interfaces well with the
    Java platform.

    Here comes a Groovy implementation of your PHP code:
    --------------
    array = [1, 2, 3, 4, 5]

    array.collect {
    it = it+1
    }
    // returns [2, 3, 4, 5]
    --------------

    Or even shorter using a range:
    --------------
    (1..5).collect {
    it = it+1
    }
    // returns [2, 3, 4, 5]
    --------------


    Kai
     
    Kai Schwebke, Jan 14, 2007
    #17
  18. Lew Guest

    Lew wrote:
    >> Anyhow, my invective aside, you can accomplish the same effect, more or less,
    >> as closures using polymorphism over an interface, as suggested by Tom Hawtin
    >> for example. I believe the formal term is a "functor" class.


    wrote:
    > Speaking on behalf of the "kiddie script" writers, everything you said
    > sailed over my head like a satellite. I have no clue what you're
    > talking about, and I happen to love eval() because it makes me write
    > one line of code instead of hundreds of lines of unmanageable code
    > every time. Can't see the entanglement, dude.

    "Script kiddies" write bad code in any language, be it assembler, Java, PHP or
    whatever. You, likely, are not actually a script kiddie, because you
    apparently use things with knowledge of your actions and their ocnsequences.

    In non-statically-typed languages eval is right in line with the language
    philosophy. Java, for all its pragmatic, seat-of-the-pants culture, is a very
    formal language. The "danger" of eval, that backward-thinking fogeys like
    myself abhor, is that it is an informal version of a closure. A "closure" is a
    formal stand-in for an arbitrary function, a kind of "function object" that
    allows similar freedom to that of eval, but is type-safe and has more compiler
    control.
    <http://en.wikipedia.org/wiki/Closure_%28computer_science%29>

    The current idioms in Java that perform that function are based on
    polymorphism: the execution of a superclass method by the subclass override.
    As Arne said, closures have some merit over the polymorphic approach. The
    debate is whether they have enough to merit inclusion in Java. He and I seem
    to agree that the advantage is outweighed by the bloat it might cause to the
    language; we seem to differ on the magnitude of the loss in not using them.

    > I don't understand quite how the code that Tom wrote works, simply
    > because I don't understand the code Tom works period, but I'll keep
    > looking into it though


    Let's review Tom's suggestion:

    Define an interface that represents any function you might have sent to
    'eval'. This is Java's equivalent to a closure:

    >> public interface Transform<T> {
    >> T transform(T value);
    >> }


    Define a class to use that interface type. Its "transform()" static method
    takes as an argument an object that implements the Transform interface. That
    object, the "functor", will do the real work with its own "transform()" method
    (same name, different method). The static transform() method does not
    understand the work but delegates it to the functor:

    public class DoesSomething
    {
    >> public <T> static void transform(
    >> List<T> values, Transform<T> transform
    >> ) {
    >> for (
    >> ListIterator<T> iter = values.listIterator();

    iter.hasNext();
    >> ) {
    >> T value = iter.next();
    >> iter.set(transform.transform(value));

    // the transform object's transform() method does the work
    >> }
    >> }
    >>

    public void someMethod()
    {
    >> List<Integer> values = Arrays.asList(new Integer[] {
    >> 1, 2, 3, 4, 5
    >> });

    /* Now pass a transform object, here defined by an anonymous inner class */
    >> transform(values, new Transform<Integer>() {
    >> public Integer transform(Integer value) {
    >> return value+1; // auto-[un]boxing
    >> }
    >> });
    >> System.out.println(values);

    }
    }

    - Lew
     
    Lew, Jan 14, 2007
    #18
  19. Tom Hawtin Guest

    wrote:
    >
    > I don't understand quite how the code that Tom wrote works, simply
    > because I don't understand the code Tom works period, but I'll keep
    > looking into it though


    Is it the use of iterators or the anonymous inner class syntax bit you
    don't understand?

    Assuming it's the anonymous inner classes, perhaps it's easier to write
    it out in full with an outer class. Obviously this can get much longer,
    and hence why inner classes were introduced.

    class IncrementTransform implements Transform<Integer>() {
    public Integer transform(Integer value) {
    return value+1;
    }
    }
    ....
    List<Integer> values
    ...
    transform(values, new IncrementTransform());



    I would generally recommend creating either a view or a transformed copy
    of the data.

    Copying we can get rid of the explicit use of iterators.

    public <T> static List<T> transform(
    List<T> src, Transform<T> transform
    ) {
    List<T> dst = new ArrayList<T>(src.size());
    -- The constructor argument is initial capacity, not size.
    for (T value : src) {
    dst.add(transform.transform(value));
    }
    return dst;
    }


    Creating a view is more complicated, but has advantages in that client
    code doesn't need to handle synchronization to the original data.

    class TransformList<T> extends java.util.AbstractList<T> {
    public static <T> List<T> asTransformed(
    List<T> target, Transform<T> transform
    ) {
    return new TransformList<T>(target, transform);
    }

    private final List<T> target;
    private final Transform<T> transform;
    private TransformList(List<T> target, Transform<T> transform) {
    if (target == null || transform == null) {
    throw new NullPointerException();
    }
    this.target = target;
    this.transform = transform;
    }
    public int size() {
    return target.size();
    }
    public T get(int index) {
    return transform.transform(target.get(index));
    }
    }

    (That code is not the most efficient possible, but should be okay so
    long as you don't start using long linked lists.)

    Tom Hawtin
     
    Tom Hawtin, Jan 14, 2007
    #19
  20. Daniel Pitts Guest

    Lew wrote:
    > As so many on this thread have pointed out, Java can do what closures do, you
    > just have to think in terms of object-orientation and polymorphism instead of
    > interpreted, loosey-goosey self-rewriting code.
    >
    > Many have argued for closures in Java. I am against them for the moment, since
    > there are already idioms that accomplish the same thing without the conceptual
    > mindtwist. Once again, that would be polymorphism, possibly with inner or
    > anonymous classes, combined with generics to provide compile-time safety.
    >
    > Java is a professional language, not a script-kiddie hack language. Things
    > like program invariants, compile-time safety and maintainability carry weight
    > here.
    >
    > - Lew


    True, but what would be the harm in having an interface:

    public interface Closure<R, P> {
    R execute(P);
    }

    and a new language feature:

    public <T> void methodWhichTakesClosure(Closure<T, T> closure);
    ....
    methodWhichTakesClosure(closure<Integer, Integer>{return arg+1; });
    which would be equivalent to:
    methodWhichTakesClosure(new Closure<Integer, Integer>() {
    Integer execute(Integer arg) {
    return arg + 1;
    }
    });

    Anything that makes the intention of the calling code clearer is a Good
    Thing(TM) in my opinion, and its just as type safe.

    While we're adding keywords and language features, maybe a shortcut to
    "Runnable" or "Callable" would be a useful idiom as well.

    SwingUtilities.invokeLater(runnable{updateGuiWith(results);});
     
    Daniel Pitts, Jan 14, 2007
    #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. Gerald Aichholzer
    Replies:
    2
    Views:
    2,597
    Gerald Aichholzer
    Jun 27, 2006
  2. Pradeep
    Replies:
    2
    Views:
    692
    Patricia Shanahan
    Jan 24, 2007
  3. Øyvind Isaksen
    Replies:
    1
    Views:
    1,012
    Øyvind Isaksen
    May 18, 2007
  4. David
    Replies:
    7
    Views:
    106
  5. Replies:
    1
    Views:
    140
Loading...

Share This Page