Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > for :each style question

Reply
Thread Tools

for :each style question

 
 
Roedy Green
Guest
Posts: n/a
 
      11-30-2011
In a for:each loop, sometimes you want to treat the first and or last
element specially.

The obvious way to handle is to revert to a for int i= loop and check
for special values of i.

You can keep the for:each style if you have a boolean first= true that
you set false to detect the first.

I don't know of an equivalent way to detect the last.

In the olden days I would have handled the first and last cases
outside the loop, with the loop running over the middle elements. You
can't do that with for:each.

What do you consider the best style to deal with this?
--
Roedy Green Canadian Mind Products
http://mindprod.com
For me, the appeal of computer programming is that
even though I am quite a klutz,
I can still produce something, in a sense
perfect, because the computer gives me as many
chances as I please to get it right.

 
Reply With Quote
 
 
 
 
Arne Vajh°j
Guest
Posts: n/a
 
      12-01-2011
On 11/30/2011 6:32 PM, Roedy Green wrote:
> In a for:each loop, sometimes you want to treat the first and or last
> element specially.
>
> The obvious way to handle is to revert to a for int i= loop and check
> for special values of i.
>
> You can keep the for:each style if you have a boolean first= true that
> you set false to detect the first.
>
> I don't know of an equivalent way to detect the last.
>
> In the olden days I would have handled the first and last cases
> outside the loop, with the loop running over the middle elements. You
> can't do that with for:each.
>
> What do you consider the best style to deal with this?


first
for first+1 to last-1
last

Not much point in for(each) when it in fact is not for each.

Arne

 
Reply With Quote
 
 
 
 
Knute Johnson
Guest
Posts: n/a
 
      12-01-2011
On 11/30/2011 3:32 PM, Roedy Green wrote:
> In a for:each loop, sometimes you want to treat the first and or last
> element specially.
>
> The obvious way to handle is to revert to a for int i= loop and check
> for special values of i.
>
> You can keep the for:each style if you have a boolean first= true that
> you set false to detect the first.
>
> I don't know of an equivalent way to detect the last.
>
> In the olden days I would have handled the first and last cases
> outside the loop, with the loop running over the middle elements. You
> can't do that with for:each.
>
> What do you consider the best style to deal with this?


public class test {
public static void main(String[] args) {
int ns[] = new int[23];
int last = 0;

for (int i=0; i<ns.length; i++)
ns[i] = i;

for (int n : ns) {
last = n;
}

System.out.println(last);
}
}

It's not elegant but it works.

--

Knute Johnson
 
Reply With Quote
 
Daniel Pitts
Guest
Posts: n/a
 
      12-01-2011
On 11/30/11 4:49 PM, Knute Johnson wrote:
> On 11/30/2011 3:32 PM, Roedy Green wrote:
>> In a for:each loop, sometimes you want to treat the first and or last
>> element specially.
>>
>> The obvious way to handle is to revert to a for int i= loop and check
>> for special values of i.
>>
>> You can keep the for:each style if you have a boolean first= true that
>> you set false to detect the first.
>>
>> I don't know of an equivalent way to detect the last.
>>
>> In the olden days I would have handled the first and last cases
>> outside the loop, with the loop running over the middle elements. You
>> can't do that with for:each.
>>
>> What do you consider the best style to deal with this?

>
> public class test {
> public static void main(String[] args) {
> int ns[] = new int[23];
> int last = 0;
>
> for (int i=0; i<ns.length; i++)
> ns[i] = i;
>
> for (int n : ns) {
> last = n;
> }
>
> System.out.println(last);
> }
> }
>
> It's not elegant but it works.
>


for:each is not useful for detecting last, and any acrobatics you go
through to fix it are fairly pointless.

You would also have to handle the case where first=last (and/or is empty).

I find specific use-cases call for different approaches. For instance,
I like the following for string concatenation:

final StringBuilder builder = new StringBuilder();

String sep = "";

for (Object o: objects) {
builder.append(sep).append(o);
sep = ", ";
}
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      12-01-2011
On 11/30/2011 6:32 PM, Roedy Green wrote:
> In a for:each loop, sometimes you want to treat the first and or last
> element specially.
>
> The obvious way to handle is to revert to a for int i= loop and check
> for special values of i.
>
> You can keep the for:each style if you have a boolean first= true that
> you set false to detect the first.
>
> I don't know of an equivalent way to detect the last.
>
> In the olden days I would have handled the first and last cases
> outside the loop, with the loop running over the middle elements. You
> can't do that with for:each.
>
> What do you consider the best style to deal with this?


I once taught a student whose DO loops (this was FORTRAN) always
iterated from 1 through N, never from 2 through N or 1 through N-1.
Paraphrasing into zero-based Java, he'd write something like

for (int i = 0; i < array.length; ++i) {
if (i == 0) continue;
if (i == array.length - 1) continue;
massage(array[i-1], array[i], array[i+1]);
}

I was unable to break him of this habit, and eventually formed
the opinion that he had learned The One True Way to write a loop,
and Nothing On Earth would persuade him to write it differently.

That's the wrong way to think about a tool.

The for:each form is a convenience, a prepackaged solution to
a common problem. Do not expect it to be the answer for all kinds
of iteration. for:each is Java's feeble imitation of (mapc); don't
push it beyond its built-in limits. There are lots of other looping
forms available; use them when they suit.

(For those who don't know what (mapc) means, see the current
thread "java developers" and give special attention to Patricia
Shanahan's contribution.)

--
Eric Sosman
http://www.velocityreviews.com/forums/(E-Mail Removed)d
 
Reply With Quote
 
Lew
Guest
Posts: n/a
 
      12-01-2011
Roedy Green wrote:
> In a for:each loop, sometimes you want to treat the first and or last
> element specially.
>
> The obvious way to handle is to revert to a for int i= loop and check
> for special values of i.
>
> You can keep the for:each style if you have a boolean first= true that
> you set false to detect the first.
>
> I don't know of an equivalent way to detect the last.
>
> In the olden days I would have handled the first and last cases
> outside the loop, with the loop running over the middle elements. You
> can't do that with for:each.
>
> What do you consider the best style to deal with this?


Regular 'for' loop (or its 'while' or 'do...while' cousins).

For:each is for a particular use case where it helps. For other use cases, you probably shouldn't use it.

--
Lew
 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      12-01-2011
On 12/01/2011 12:32 AM, Roedy Green wrote:
> In a for:each loop, sometimes you want to treat the first and or last
> element specially.
>
> The obvious way to handle is to revert to a for int i= loop and check
> for special values of i.
>
> You can keep the for:each style if you have a boolean first= true that
> you set false to detect the first.
>
> I don't know of an equivalent way to detect the last.


The trick for detecting the last element is to defer evaluation of each
element by one iteration and handle the last one after the loop.

> In the olden days I would have handled the first and last cases
> outside the loop, with the loop running over the middle elements. You
> can't do that with for:each.
>
> What do you consider the best style to deal with this?


For the fun of it, here is one way to do it - although I find it quite
silly:

package clj;

import java.util.Arrays;

public final class FirstLast {

private static enum Pos {
NONE, FIRST, LATER
}

public static <T> void firstLast(final Iterable<T> items) {
Pos p = Pos.NONE;
T last = null;

for (final T item : items) {
switch (p) {
case NONE:
p = Pos.FIRST;
break;
case FIRST:
System.out.println("First: " + last);
p = Pos.LATER;
break;
case LATER:
System.out.println("Next: " + last);
break;
}

last = item;
}

if (p != Pos.NONE) {
System.out.println("Last: " + last);
}
}

public static void main(String[] args) {
System.out.println("empty");
firstLast(Arrays.asList());
System.out.println("one");
firstLast(Arrays.asList("a"));
System.out.println("two");
firstLast(Arrays.asList("a", "b"));
System.out.println("more");
firstLast(Arrays.asList("a", "b", "c", "d"));
}

}

Kind regards

robert
 
Reply With Quote
 
Steven Simpson
Guest
Posts: n/a
 
      12-04-2011
On 30/11/11 23:32, Roedy Green wrote:
> In a for:each loop, sometimes you want to treat the first and or last
> element specially. [...]
> What do you consider the best style to deal with this?


If I needed it a lot...

import java.util.Arrays;
import java.util.List;

public class FirstLastLoop {
interface FirstLastBlock<T> {
void invoke(T t, boolean isFirst, boolean isLast);
}

static<T> void forEach(Iterable<? extends T> coll,
FirstLastBlock<? super T> block) {
boolean isFirst = true;
boolean lastHeld = false;
T last = null;
for (T t : coll) {
if (lastHeld) {
block.invoke(last, isFirst, false);
isFirst = false;
}

last = t;
lastHeld = true;
}
if (lastHeld)
block.invoke(last, isFirst, true);
}

public static void main(String[] args) throws Exception {
List<String> list = Arrays.asList(args);

FirstLastBlock<String> block = new FirstLastBlock<String>() {
public void invoke(String t, boolean isFirst, boolean isLast) {
if (isFirst)
System.out.print("The list: ");
else if (isLast)
System.out.print(" and ");
else
System.out.print(", ");
System.out.print(t);
if (isLast)
System.out.println('.');
}
};

forEach(list, block);

// Lambda version
forEach(list, (t, isFirst, isLast) -> {
if (isFirst)
System.out.print("The list: ");
else if (isLast)
System.out.print(" and ");
else
System.out.print(", ");
System.out.print(t);
if (isLast)
System.out.println('.');
});
}
}



--
ss at comp dot lancs dot ac dot uk

 
Reply With Quote
 
Chris Riesbeck
Guest
Posts: n/a
 
      12-05-2011
On 11/30/2011 6:28 PM, Arne Vajh°j wrote:
> On 11/30/2011 6:32 PM, Roedy Green wrote:
>> In a for:each loop, sometimes you want to treat the first and or last
>> element specially.
>>
>> The obvious way to handle is to revert to a for int i= loop and check
>> for special values of i.
>>
>> You can keep the for:each style if you have a boolean first= true that
>> you set false to detect the first.
>>
>> I don't know of an equivalent way to detect the last.
>>
>> In the olden days I would have handled the first and last cases
>> outside the loop, with the loop running over the middle elements. You
>> can't do that with for:each.
>>
>> What do you consider the best style to deal with this?

>
> first
> for first+1 to last-1
> last
>
> Not much point in for(each) when it in fact is not for each.
>


While it's not a Java for:each loop, it's well within the concept of for
each loops in general. The JSTL foreach element has some optional syntax
for accessing just this kind of data :

<c:forEach var="person" items="${group.members}" varStatus="status">
...
</c:forEach>

Inside the forEach, status can tell you if you're first, last, etc.

http://www.ibm.com/developerworks/ja...ry/j-jstl0318/

There are a couple of things I wish Java's for:each did. The other
biggie is looping across several collections in parallel.

 
Reply With Quote
 
Daniel Pitts
Guest
Posts: n/a
 
      12-12-2011
On 12/10/11 4:28 AM, Wanja Gayk wrote:
> In article<iyBBq.2059$(E-Mail Removed)>,
> (E-Mail Removed) says...
>
>> I find specific use-cases call for different approaches. For instance,
>> I like the following for string concatenation:
>>
>> final StringBuilder builder = new StringBuilder();
>>
>> String sep = "";
>>
>> for (Object o: objects) {
>> builder.append(sep).append(o);
>> sep = ", ";
>> }

>
> I always preferred to do it this way:
>
> final StringBuilder builder = new StringBuilder();
> final String sep = ", ";
> for (final Object o: objects) {
> builder.append(o).append(sep);
> }
> builder.setLength(Math.max(0,builder.length()-sep.length()));
>
> The only drawback is that the size of the builder's internal buffer may
> grow unnecessarily, if the last separator crosses its current bounds,
> but how often does that happen and how often is it really a problem?

The *only* drawback? Having to invoke a "Math" command is a drawback
IMO. I like my approach because you can have a different starting
separator. Consider the case where you want parenthesis for one or
more items, but an empty string for no items.:

String ender = "";
String sep = "(";
for (Object o: objects) {
builder.append(sep).append(o);
sep=", "; end=")";
}
builder.append(end);

Builds a parenthesized comma-separated list. I have used this pattern
frequently for SQL or HQL query builders.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
DataGrid header style inconsistent with sortable column style cedoucette@alum.rpi.edu ASP .Net 0 10-14-2005 12:13 AM
All style tags after the first 30 style tags on an HTML page are not applied in Internet Explorer Rob Nicholson ASP .Net 3 05-28-2005 03:11 PM
Need help with Style conversion from Style object to Style key/value collection. Ken Varn ASP .Net Building Controls 0 04-26-2004 07:06 PM
Javascript Style Switcher that remebers current site style in use Hardeep Rakhra HTML 8 01-15-2004 08:00 PM
Style sheets, include one style within another (not inheritance) foldface@yahoo.co.uk HTML 1 11-24-2003 01:37 PM



Advertisments