Re: Using filter with std.container.Array.

2017-03-22 Thread Soulsbane via Digitalmars-d-learn
On Thursday, 23 March 2017 at 03:02:54 UTC, Jonathan M Davis 
wrote:
On Thursday, March 23, 2017 02:53:40 Soulsbane via 
Digitalmars-d-learn wrote:

[...]


find just iterates to the first element that matches. It 
doesn't affect the range beyond that. It works basically the 
same way that find would work with iterators in that it 
iterates until it finds the element you're looking for. 
However, since ranges then refer to more than one element at a 
time, the rest of the range beyond that element is still there.


[...]


Thanks a lot for the explanation. It's much clearer to me now! 
You've been a big help.


Re: Using filter with std.container.Array.

2017-03-22 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, March 23, 2017 02:53:40 Soulsbane via Digitalmars-d-learn 
wrote:
> Thanks for the reply Jonathan! Yes, I was trying to find all the
> ids that match but couldn't get find to work. So I think I have
> missed something somewhere.
>
> As a quick example:
> import std.stdio;
> import std.algorithm;
> import std.container;
>
> struct Foo
> {
>string name;
>size_t id;
> }
>
> Array!Foo foo_;
>
> void main(string[] arguments)
> {
>   Foo first;
>   first.id = 200;
>
>   Foo second;
>   second.id = 100;
>
>   Foo third;
>   third.id = 345;
>
>   Foo fourth;
>   fourth.id = 100;
>
>   foo_.insert(first);
>   foo_.insert(second);
>   foo_.insert(third);
>   foo_.insert(fourth);
>
>   auto filterIt = filter!((Foo data) => data.id == 100)(foo_[]);
>   auto foundIt = find!((Foo data) => data.id == 100)(foo_[]);
>   writeln(filterIt);
>   writeln(foundIt);
> }
>
> Will print:
> [Foo("", 100), Foo("", 100)]
> [Foo("", 100), Foo("", 345), Foo("", 100)]
>
> I only want the ids that match 100. Looking at find's
> documentation it looks like it's returning exactly as it should
> but not the way I want. No 345 id.
>
> Thanks for the help. I have this code working just fine using
> foreach and have been trying to learn this different way of doing
> things lately and my brain hurts :). Thanks again.

find just iterates to the first element that matches. It doesn't affect the
range beyond that. It works basically the same way that find would work with
iterators in that it iterates until it finds the element you're looking for.
However, since ranges then refer to more than one element at a time, the
rest of the range beyond that element is still there.

filter, on the other hand, creates a lazy range which skips the elements in
the original range which do not match the predicate. It doesn't actually do
anything until you iterate over it.

So, if you're looking specifically for _all_ of the elements in a range
which match a predicate and no other elements from that range (as it sounds
like you're doing), then filter is the correct choice. If, on the other
hand, you just want to find the first element that matches and then do
who-knows-what with the rest of the range, then find would be appropriate.

Note that because filter is lazy, it results in a new range which wraps the
original, whereas find returns the original range with elements popped off.

- Jonathan M Davis



Re: Using filter with std.container.Array.

2017-03-22 Thread Soulsbane via Digitalmars-d-learn
On Wednesday, 22 March 2017 at 07:30:48 UTC, Jonathan M Davis 
wrote:
On Wednesday, March 22, 2017 07:06:47 Soulsbane via 
Digitalmars-d-learn wrote:

Example code:
struct Foo
{
   string name;
   size_t id;
}

Array!Foo foo_;

I get errors when I try to use filter like this:

auto found = filter!((Foo data, size_t id) => data.id ==
id)(foo_[], 100);

I get this error
source/app.d(15,62): Error: template
std.algorithm.iteration.filter!(function (Foo data, ulong id) 
=>
data.id == id).filter cannot deduce function from argument 
types

!()(RangeT!(Array!(Foo)), int), candidates are:
/usr/include/dmd/phobos/std/algorithm/iteration.d(1089,10):
  std.algorithm.iteration.filter!(function (Foo data, ulong 
id) =>

data.id == id).filter(Range)(Range range) if
(isInputRange!(Unqual!Range))

I can't figure out what I'm doing wrong. Thanks!


filter takes a unary predicate that gets called on each element 
in a range. It's not going to work with a function that takes 
two arguments, and filter itself isn't going to take two 
arguments. You could do something like


auto result = filter!(a => a.id == 100)(foo_[]);

but you can't pass multiple arguments to filter. Also, if 
you're looking to find an element, then find would make more 
sense than filter, since filter is going to give you a lazy 
range with every element that matches the predicate, whereas 
find is just going to iterate the range until it finds the 
element (or is empty) and then returns the range. But I don't 
know whether calling the variable found was just the name you 
came up with or whether you're really trying to do a find 
operation rather than filter.


- Jonathan M Davis


Thanks for the reply Jonathan! Yes, I was trying to find all the 
ids that match but couldn't get find to work. So I think I have 
missed something somewhere.


As a quick example:
import std.stdio;
import std.algorithm;
import std.container;

struct Foo
{
  string name;
  size_t id;
}

Array!Foo foo_;

void main(string[] arguments)
{
Foo first;
first.id = 200;

Foo second;
second.id = 100;

Foo third;
third.id = 345;

Foo fourth;
fourth.id = 100;

foo_.insert(first);
foo_.insert(second);
foo_.insert(third);
foo_.insert(fourth);

auto filterIt = filter!((Foo data) => data.id == 100)(foo_[]);
auto foundIt = find!((Foo data) => data.id == 100)(foo_[]);
writeln(filterIt);
writeln(foundIt);
}

Will print:
[Foo("", 100), Foo("", 100)]
[Foo("", 100), Foo("", 345), Foo("", 100)]

I only want the ids that match 100. Looking at find's 
documentation it looks like it's returning exactly as it should 
but not the way I want. No 345 id.


Thanks for the help. I have this code working just fine using 
foreach and have been trying to learn this different way of doing 
things lately and my brain hurts :). Thanks again.




Re: Using filter with std.container.Array.

2017-03-22 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, March 22, 2017 07:06:47 Soulsbane via Digitalmars-d-learn 
wrote:
> Example code:
> struct Foo
> {
>string name;
>size_t id;
> }
>
> Array!Foo foo_;
>
> I get errors when I try to use filter like this:
>
> auto found = filter!((Foo data, size_t id) => data.id ==
> id)(foo_[], 100);
>
> I get this error
> source/app.d(15,62): Error: template
> std.algorithm.iteration.filter!(function (Foo data, ulong id) =>
> data.id == id).filter cannot deduce function from argument types
> !()(RangeT!(Array!(Foo)), int), candidates are:
> /usr/include/dmd/phobos/std/algorithm/iteration.d(1089,10):
>   std.algorithm.iteration.filter!(function (Foo data, ulong id) =>
> data.id == id).filter(Range)(Range range) if
> (isInputRange!(Unqual!Range))
>
> I can't figure out what I'm doing wrong. Thanks!

filter takes a unary predicate that gets called on each element in a range.
It's not going to work with a function that takes two arguments, and filter
itself isn't going to take two arguments. You could do something like

auto result = filter!(a => a.id == 100)(foo_[]);

but you can't pass multiple arguments to filter. Also, if you're looking to
find an element, then find would make more sense than filter, since filter
is going to give you a lazy range with every element that matches the
predicate, whereas find is just going to iterate the range until it finds
the element (or is empty) and then returns the range. But I don't know
whether calling the variable found was just the name you came up with or
whether you're really trying to do a find operation rather than filter.

- Jonathan M Davis