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

P

phillip.s.powell

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

phillip.s.powell

Paul said:
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
 
T

Tom Hawtin

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
 
R

Rogan Dawes

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
 
P

phillip.s.powell

Rogan said:
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
 
P

Patricia Shanahan

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
 
M

Mark Rafn

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

Daniel Pitts

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

Eric Sosman

Paul said:
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.
 
R

RedGrittyBrick

Daniel said:
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; }
});
 
L

Lew

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
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Lew said:
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.
 
L

Lew

(followup set to clj.programmer, as we proceed into a little more theoretical
domain.)
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
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

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
 
P

phillip.s.powell

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


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
 
P

phillip.s.powell

Eric said:
Paul said:
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?
 
K

Kai Schwebke

<?
$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]
 
L

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.
"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_(computer_science)>

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:

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

Tom Hawtin

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
 
D

Daniel Pitts

Lew said:
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);});
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top