From: Keith Thompson on
"bart.c" <bartc(a)freeuk.com> writes:
> "Keith Thompson" <kst-u(a)mib.org> wrote in message
> news:lnr5lpvyp8.fsf(a)nuthaus.mib.org...
>> "bart.c" <bartc(a)freeuk.com> writes:
>>> "Nathan Baker" <nathancbaker(a)gmail.com> wrote in message
>>> news:NamdnYqxi6pkH3_WnZ2dnUVZ_oydnZ2d(a)giganews.com...
>>> Except the memory layout might not be linear: each inner row might be
>>> allocated in a different place.
>>
>> No, C arrays are contiguous.
>
> Flat arrays, yes. But it sounded like this 3D array consisted of
> pointers to pointers.

You're right, that's certainly possible. And since the original
code is C++ (note that this thread is cross-posted), the [] and
other operators could be overloaded.

--
Keith Thompson (The_Other_Keith) kst-u(a)mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
From: Juha Nieminen on
In comp.lang.c++ Nathan <nathancbaker(a)gmail.com> wrote:
> On Apr 28, 1:16�am, Juha Nieminen <nos...(a)thanks.invalid> wrote:
>> Value_t* MyClass::findValue(const Value_t& value)
>> {
>> for(size_t xInd = 0; xInd < data.size(); ++xInd)
>> for(size_t yInd = 0; yInd < data[xInd].size(); ++yInd)
>> for(size_t zInd = 0; zInd < data[xInd][yInd].size(); ++zInd)
>> {
>> if(data[xInd][yInd][zInd] == value)
>> return &data[xInd][yInd][zInd];
>> }
>>
>> return 0;
>> }
>
> Hi Juha,
>
> I think that you either copied this from a poorly-written beginner C++
> book or you failed to understand what the author was attempting to
> demonstrate with that kind of code and that you did not 'catch on'
> that it is not (in any way) demonstrative of how one walks a series of
> sequential cells in the real world.

I don't know if you are being sarcastic, patronizing, or honestly don't
know what you are talking about, but I'll let it pass.

> Why do you insist on writing control structures that serve little
> actual purpose? For instance, it should be obvious that you only
> require ONE loop and a few conditionals to achieve your desired (or
> assumed) goal. E.G...
>
> ,---
> result = value
> xInd = 0
> yInd = 0
> zInd = 0
> while ( data[xInd][yInd][zInd] != value && result != 0)
> {
> ++zInd;
> if (( zInd < data[xInd][yInd].size() ) != true ) { zInd = 0; +
> +yInd};
> if (( yInd < data[xInd].size() ) != true ) { yInd = 0; ++xInd};
> if (( xInd < data.size() ) != true ) { result = 0 };
> }
> return result
> `---

The goal was to make the function simpler, not more complicated.
Your version (even if it's fixed to actually do the same thing, and even
after removing the superfluous conditionals) is significantly more
complicated for many reasons. Most importantly, it uses a strange idiom
which the vast majority of programmers are not familiar with and don't
use (and why would they?) It takes significantly more time to understand
what your code is doing, as well as to verify that it's doing it correctly.
My original version with three nested loops is a lot easier to understand,
and a lot easier to verify that it works correctly.

And what for? It's not more efficient, shorter or does it do anything
that the original wouldn't do. Moreover, it's very possible that in some
similar circumstances a compile could be able to perform better optimizations
on the original nested loop version than yours (eg. by applying loop
unrolling and other optimization techniques).

> Of course, this is a rather useless (maybe even retarded) function to
> begin with, because it only tells you IF the 'value' is located
> "somewhere" within that array -- it gives you absolutely no indication
> of "where" in that array you might be able to access the item which
> matches your search criteria.

Actually the function returns a pointer to the found element, or null
if the element is not found.
From: Juha Nieminen on
In comp.lang.c++ Nathan <nathancbaker(a)gmail.com> wrote:
> Well, 'y < x' must evaluate as 'true' in order for something to be
> classified as simpler. So, because *one loop* < *three loops*, my
> version certainly looks simpler. [e.g. less opcodes in the generated
> binary ]

"Simpler" does not mean "produces a smaller executable file" or "has
less loops". "Simpler" means "easier to understand".

Your version may have less loops, but you have replaced them with
complex conditional statements, which are unusual and useless (because
they don't do anything the loops weren't doing already).

(Ironically, your version is also less efficient because it performs
all three index range checks at each iteration, while the nested loop
version does only one index range check for the innermost iteration.)

>> More importantly, it can dereference index [0] before checking size(),
>> so produces undefined behaviour. �Anyway, IMHO it's far less clear
>> (=self-evidently correct & efficient as well as maintainable) than
>> Juha's code.
>>
>
> More maintainable by the original coder... or more maintainable by
> someone 'new' to the code??? If this function were many screens in
> length, and someone 'new' decides to have it perform an extra task
> 'just' before returning, wouldn't that person have a "devil of a time"
> debugging the program if he were not aware of the hidden alternative
> 'return' route tucked-away in that nest?

Even if you had an understandability problem with a "hidden return",
the correct solution is not to make the whole thing an unusual and hard
to understand construct which is probably even less efficient.

> Yes, rather than waste one's time bickering about the various esteemed
> implementation alternatives of a particular algo, why not consider an
> algo that renders those salient points mute?

Because the whole point of this thread is "how to exit nested loops
most cleanly?", not "what is the best way of doing task X?"
From: Nick on
Juha Nieminen <nospam(a)thanks.invalid> writes:

> In comp.lang.c++ Nathan <nathancbaker(a)gmail.com> wrote:
>> Well, 'y < x' must evaluate as 'true' in order for something to be
>> classified as simpler. So, because *one loop* < *three loops*, my
>> version certainly looks simpler. [e.g. less opcodes in the generated
>> binary ]
>
> "Simpler" does not mean "produces a smaller executable file" or "has
> less loops". "Simpler" means "easier to understand".
>
> Your version may have less loops, but you have replaced them with
> complex conditional statements, which are unusual and useless (because
> they don't do anything the loops weren't doing already).
>
> (Ironically, your version is also less efficient because it performs
> all three index range checks at each iteration, while the nested loop
> version does only one index range check for the innermost iteration.)

Particularly if that "size()" function involves a counting loop rather
than a value lookup.
--
Online waterways route planner | http://canalplan.eu
Plan trips, see photos, check facilities | http://canalplan.org.uk
From: Daniel T. on
Keith Thompson <kst-u(a)mib.org> wrote:
> Nathan <nathancbaker(a)gmail.com> writes:
>
> > ,---
> > result = value
> > xInd = 0
> > yInd = 0
> > zInd = 0
> > while ( data[xInd][yInd][zInd] != value && result != 0)
> > {
> > ++zInd;
> > if (( zInd < data[xInd][yInd].size() ) != true ) { zInd = 0; +
> > +yInd};
> > if (( yInd < data[xInd].size() ) != true ) { yInd = 0; ++xInd};
> > if (( xInd < data.size() ) != true ) { result = 0 };
> > }
> > return result
> > `---
> [...]
>
> A style point: comparisons to true and false are almost always
> superfluous. Rather than
> if (( xInd < data.size() ) != true )
> just write
> if ( xInd <= data.size() )
>
> As for the overall structure of your proposed replacement, you've
> replaced three nested loops with one loop and three if statements.
> Furthermore, the original version only tests zInd on most iterations;
> your version tests zInd, yInd, and xInd on every iteration.

However, his version could easily be modified so it didn't make the
extra tests... As you probably know.

> The original problem is to traverse a 3-dimensional array. A triple
> nested loop is the most obvious way to do that. There might be
> some advantages in converting it to a single loop, but clarity
> isn't one of them, at least in this case.

I think there is some confusion here, the original problem is to return
the first element in the container that equals a particular value. Using
three loops to iterate through one container is unnecessary. i.e.,

iterator result = data.begin();
while (result != data.end() && *result != value)
++result;
return result;

A solution very much like the above could even be done in C on an actual
three dimensional array...