www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Using filter with std.container.Array.

reply Soulsbane <paul acheronsoft.com> writes:
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!
Mar 22 2017
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
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
Mar 22 2017
parent reply Soulsbane <paul acheronsoft.com> writes:
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.
Mar 22 2017
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
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
Mar 22 2017
parent Soulsbane <paul acheronsoft.com> writes:
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.
Mar 22 2017