www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Strange output

reply "Daemon" <daemon yahoo.com> writes:
The following program is supposed to print out only numbers that 
are less than 5, yet the number 63 gets printed.

module main;

import std.stdio;
import std.conv;

int main(string[] argv)
{
	auto de = find!(delegate(a) { return a < 5; })([10, 11, 15, 16, 
27, 20, 2, -4, -17, 8, 64, 6]);

	foreach (int b; de[0 .. $])
	{
		writeln(b);
	}
	
	readln();

     return 0;
}

T[] find(alias pred, T)(T[] input)
	if (is(typeof(pred(input[0])) == bool))
{
	for (; input.length > 0; input = input[1 .. $])
	{
		if (pred(input[0]))
		{
			break;
		}
	}
	return input;
}

I realize it's extremely improbable that I've discovered a bug, 
so what exactly could I be doing wrong? Why is the output:

2
-4
-17
8
63
6

I'm probably missing something obvious. If the input is just 
[63], then nothing gets printed out.
Jun 07 2013
next sibling parent "Daemon" <daemon yahoo.com> writes:
 auto de = find!(delegate(a) { return a < 5; })([10, 11, 15, 16, 
 27, 20, 2, -4, -17, 8, 64, 6]);
Just a clarification, it prints out 64 with the input above, I changed it later just to test it and forgot to update the rest.
Jun 07 2013
prev sibling next sibling parent reply "develop32" <develop32 gmail.com> writes:
On Friday, 7 June 2013 at 19:10:54 UTC, Daemon wrote:
 The following program is supposed to print out only numbers 
 that are less than 5, yet the number 63 gets printed.

 module main;

 import std.stdio;
 import std.conv;

 int main(string[] argv)
 {
 	auto de = find!(delegate(a) { return a < 5; })([10, 11, 15, 
 16, 27, 20, 2, -4, -17, 8, 64, 6]);

 	foreach (int b; de[0 .. $])
 	{
 		writeln(b);
 	}
 	
 	readln();

     return 0;
 }

 T[] find(alias pred, T)(T[] input)
 	if (is(typeof(pred(input[0])) == bool))
 {
 	for (; input.length > 0; input = input[1 .. $])
 	{
 		if (pred(input[0]))
 		{
 			break;
 		}
 	}
 	return input;
 }

 I realize it's extremely improbable that I've discovered a bug, 
 so what exactly could I be doing wrong? Why is the output:

 2
 -4
 -17
 8
 63
 6

 I'm probably missing something obvious. If the input is just 
 [63], then nothing gets printed out.
It looks like your find function just stops at the first item that is less than five (which is two) and returns a range consisting of all the following items. If you'll look closer, your output is just all items after and including 2.
Jun 07 2013
parent "Daemon" <daemon yahoo.com> writes:
On Friday, 7 June 2013 at 19:47:39 UTC, develop32 wrote:
 On Friday, 7 June 2013 at 19:10:54 UTC, Daemon wrote:
 The following program is supposed to print out only numbers 
 that are less than 5, yet the number 63 gets printed.

 module main;

 import std.stdio;
 import std.conv;

 int main(string[] argv)
 {
 	auto de = find!(delegate(a) { return a < 5; })([10, 11, 15, 
 16, 27, 20, 2, -4, -17, 8, 64, 6]);

 	foreach (int b; de[0 .. $])
 	{
 		writeln(b);
 	}
 	
 	readln();

    return 0;
 }

 T[] find(alias pred, T)(T[] input)
 	if (is(typeof(pred(input[0])) == bool))
 {
 	for (; input.length > 0; input = input[1 .. $])
 	{
 		if (pred(input[0]))
 		{
 			break;
 		}
 	}
 	return input;
 }

 I realize it's extremely improbable that I've discovered a 
 bug, so what exactly could I be doing wrong? Why is the output:

 2
 -4
 -17
 8
 63
 6

 I'm probably missing something obvious. If the input is just 
 [63], then nothing gets printed out.
It looks like your find function just stops at the first item that is less than five (which is two) and returns a range consisting of all the following items. If you'll look closer, your output is just all items after and including 2.
I totally misunderstood the for loop before, I feel ashamed. Thanks a lot, haha
Jun 07 2013
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Jun 07, 2013 at 09:10:53PM +0200, Daemon wrote:
 The following program is supposed to print out only numbers that are
 less than 5, yet the number 63 gets printed.
On Fri, Jun 07, 2013 at 09:14:00PM +0200, Daemon wrote:
auto de = find!(delegate(a) { return a < 5; })([10, 11, 15, 16,
27, 20, 2, -4, -17, 8, 64, 6]);
Just a clarification, it prints out 64 with the input above, I changed it later just to test it and forgot to update the rest.
This should not be surprising. Please see my comments below:
 module main;
 
 import std.stdio;
 import std.conv;
 
 int main(string[] argv)
 {
 	auto de = find!(delegate(a) { return a < 5; })([10, 11, 15, 16, 27,
 20, 2, -4, -17, 8, 64, 6]);
 
OK, so here 'de' is assigned whatever is returned by 'find', and the following loop prints out its contents. The question then is, what does find() return?
 	foreach (int b; de[0 .. $])
 	{
 		writeln(b);
 	}
 	
 	readln();
 
     return 0;
 }
 
 T[] find(alias pred, T)(T[] input)
 	if (is(typeof(pred(input[0])) == bool))
 {
 	for (; input.length > 0; input = input[1 .. $])
OK, so what the above is saying, is that you want to loop over the input array, and reduce it by one element each time (i.e. slice from 1 to the end). So let's look at the input main() is giving it: [10, 11, 15, ...]. So the first time round, we're looking at the entire array, which starts with the element 10.
 	{
 		if (pred(input[0]))
 		{
 			break;
 		}
So here, 'pred' is passed the value of input[0]. The first time round, input[0] is 10, so pred returns false: because 10 < 5 is false. So the loop runs again, and the next time round, the array has been shortened to [11, 15, ...]. So now, input[0] is 11, and again, 11 < 5 is false, so the loop keeps running. Now what happens after the next few iterations, when you get to '2'? At that point, input looks like this: [2, -4, -17, 8, 64, 6]. So input[0] is 2, and since 2 < 5, pred(input[0]) returns true. So the next line says 'break', which means "stop running the loop". Remember that at this point, input is [2, -4, -17, 8, 64, 6]. And then finally:
 	}
 	return input;
 }
This says, return input (which is currently [2, -4, -17, 8, 64, 6]). So going back to main(), we see that 'de' must be [2, -4, -17, 8, 64, 6]. And indeed, that's the output you get. So the program isn't doing anything wrong. It's just that what you wrote isn't quite what you wanted. :) It sounds like you wanted to *filter* the array for elements less than 5. So what you need to do is, once you find an element that's 5 or greater, you need to skip over it. However, a D array is a *contiguous* list of elements; there's no such thing as a skipped element in an array. So you can't just return a slice of the original array -- a slice is also a contiguous block of elements; while it *can* give you a "sub-array" view of the original array, it cannot start somewhere, skip over some elements, and then continue. The easiest solution is to construct a new array that doesn't have the offending elements, maybe something along these lines: T[] find(alias pred, T)(T[] input) if (is(typeof(pred(input[0])) == bool)) { // Note this line: we're creating a new array containing only // the elements we want. T[] result; for (; input.length > 0; input = input[1 .. $]) { if (pred(input[0])) { // Found an element that satisfies our // predicate, so append that to the end of our // results. result ~= input[0]; // (No break here: we want to look at every // element in the input.) } } // N.B.: instead of returning input, which is a slice of the // original array, we return the new array we've constructed // that only has the elements we want. return result; } Hope this helps! T -- Freedom of speech: the whole world has no right *not* to hear my spouting off!
Jun 07 2013
parent "Daemon" <daemon yahoo.com> writes:
On Friday, 7 June 2013 at 20:06:32 UTC, H. S. Teoh wrote:
 On Fri, Jun 07, 2013 at 09:10:53PM +0200, Daemon wrote:
 The following program is supposed to print out only numbers 
 that are
 less than 5, yet the number 63 gets printed.
On Fri, Jun 07, 2013 at 09:14:00PM +0200, Daemon wrote:
auto de = find!(delegate(a) { return a < 5; })([10, 11, 15, 
16,
27, 20, 2, -4, -17, 8, 64, 6]);
Just a clarification, it prints out 64 with the input above, I changed it later just to test it and forgot to update the rest.
This should not be surprising. Please see my comments below:
 module main;
 
 import std.stdio;
 import std.conv;
 
 int main(string[] argv)
 {
 	auto de = find!(delegate(a) { return a < 5; })([10, 11, 15, 
 16, 27,
 20, 2, -4, -17, 8, 64, 6]);
 
OK, so here 'de' is assigned whatever is returned by 'find', and the following loop prints out its contents. The question then is, what does find() return?
 	foreach (int b; de[0 .. $])
 	{
 		writeln(b);
 	}
 	
 	readln();
 
     return 0;
 }
 
 T[] find(alias pred, T)(T[] input)
 	if (is(typeof(pred(input[0])) == bool))
 {
 	for (; input.length > 0; input = input[1 .. $])
OK, so what the above is saying, is that you want to loop over the input array, and reduce it by one element each time (i.e. slice from 1 to the end). So let's look at the input main() is giving it: [10, 11, 15, ...]. So the first time round, we're looking at the entire array, which starts with the element 10.
 	{
 		if (pred(input[0]))
 		{
 			break;
 		}
So here, 'pred' is passed the value of input[0]. The first time round, input[0] is 10, so pred returns false: because 10 < 5 is false. So the loop runs again, and the next time round, the array has been shortened to [11, 15, ...]. So now, input[0] is 11, and again, 11 < 5 is false, so the loop keeps running. Now what happens after the next few iterations, when you get to '2'? At that point, input looks like this: [2, -4, -17, 8, 64, 6]. So input[0] is 2, and since 2 < 5, pred(input[0]) returns true. So the next line says 'break', which means "stop running the loop". Remember that at this point, input is [2, -4, -17, 8, 64, 6]. And then finally:
 	}
 	return input;
 }
This says, return input (which is currently [2, -4, -17, 8, 64, 6]). So going back to main(), we see that 'de' must be [2, -4, -17, 8, 64, 6]. And indeed, that's the output you get. So the program isn't doing anything wrong. It's just that what you wrote isn't quite what you wanted. :) It sounds like you wanted to *filter* the array for elements less than 5. So what you need to do is, once you find an element that's 5 or greater, you need to skip over it. However, a D array is a *contiguous* list of elements; there's no such thing as a skipped element in an array. So you can't just return a slice of the original array -- a slice is also a contiguous block of elements; while it *can* give you a "sub-array" view of the original array, it cannot start somewhere, skip over some elements, and then continue. The easiest solution is to construct a new array that doesn't have the offending elements, maybe something along these lines: T[] find(alias pred, T)(T[] input) if (is(typeof(pred(input[0])) == bool)) { // Note this line: we're creating a new array containing only // the elements we want. T[] result; for (; input.length > 0; input = input[1 .. $]) { if (pred(input[0])) { // Found an element that satisfies our // predicate, so append that to the end of our // results. result ~= input[0]; // (No break here: we want to look at every // element in the input.) } } // N.B.: instead of returning input, which is a slice of the // original array, we return the new array we've constructed // that only has the elements we want. return result; } Hope this helps! T
Thanks a lot for the clarification of the arrays, that really got me confused for a while!
Jun 08 2013
prev sibling parent "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Friday, 7 June 2013 at 19:10:54 UTC, Daemon wrote:
 The following program is supposed to print out only numbers 
 that are less than 5, yet the number 63 gets printed.
You're probably just playing around, but FYI the function is http://dlang.org/phobos/std_algorithm.html#filter While you've created the same find already in std.algorithm.
Jun 07 2013