www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Best way to check for an element in an array?

reply "Taylor Hillegeist" <taylorh140 gmail.com> writes:
So I find myself Doing this kind of thing very frequently. I have 
a Array of Somethings and i want to see if "something specific" 
is inside the array. I wrote a template for it. but is this the 
best way to do this kind of thing. I feel like it doesn't help 
with readability. Is there a better way? Maybe i missed something 
in the std library.

import std.stdio;

template FNDR(T){
     bool isIn(T Element, T[] Array){
         bool rtn=false;
         foreach(T ArrayElement; Array){
             if(Element==ArrayElement){
                 rtn=true;
             }
         }
     return rtn;
     }
}

void main(string[] args)
{
     int[3] stuff=[0,1,2];
     if (FNDR!int.isIn(2,stuff))
     {
         writeln("Hello World!");
     }
}


Is there a way maybe to make it look like this?

import std.stdio;

template FNDR(T){
     bool contains(T[] Array,T Element){
         bool rtn=false;
         foreach(T ArrayElement; Array){
             if(Element==ArrayElement){
                 rtn=true;
             }
         }
     return rtn;
     }
}

void main(string[] args)
{
     int[3] stuff=[0,1,2];
     if (stuff.contains(2)) // Much clean! 
stuff.FNDR!int.contains(2) doesn't work
     {
         writeln("Hello World!");
     }
}

I'm interested in what you guys think? what is the cleanest way 
to do this?
Apr 21 2014
next sibling parent reply Timothee Cour via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
you can use stuff.canFind(2)

but sometimes it'd be more convenient to have the other way around (UFCS
chains etc);

how about:

bool isIn(T,T2...)(T needle, T2 haystack)
if(__traits(compiles,T.init==T2[0].init)){
  foreach(e;haystack){
    if(needle==e) return true;
  }
  return false;
}
unittest{
assert(1.isIn(3,1,2) && !4.isIn(3,1,2));
}





On Mon, Apr 21, 2014 at 8:25 PM, Taylor Hillegeist via Digitalmars-d-learn <
digitalmars-d-learn puremagic.com> wrote:

 So I find myself Doing this kind of thing very frequently. I have a Array
 of Somethings and i want to see if "something specific" is inside the
 array. I wrote a template for it. but is this the best way to do this kind
 of thing. I feel like it doesn't help with readability. Is there a better
 way? Maybe i missed something in the std library.

 import std.stdio;

 template FNDR(T){
     bool isIn(T Element, T[] Array){
         bool rtn=false;
         foreach(T ArrayElement; Array){
             if(Element==ArrayElement){
                 rtn=true;
             }
         }
     return rtn;
     }
 }

 void main(string[] args)
 {
     int[3] stuff=[0,1,2];
     if (FNDR!int.isIn(2,stuff))
     {
         writeln("Hello World!");
     }
 }


 Is there a way maybe to make it look like this?

 import std.stdio;

 template FNDR(T){
     bool contains(T[] Array,T Element){
         bool rtn=false;
         foreach(T ArrayElement; Array){
             if(Element==ArrayElement){
                 rtn=true;
             }
         }
     return rtn;
     }
 }

 void main(string[] args)
 {
     int[3] stuff=[0,1,2];
     if (stuff.contains(2)) // Much clean! stuff.FNDR!int.contains(2)
 doesn't work
     {
         writeln("Hello World!");
     }
 }

 I'm interested in what you guys think? what is the cleanest way to do this?
Apr 21 2014
parent reply "Taylor Hillegeist" <taylorh140 gmail.com> writes:
On Tuesday, 22 April 2014 at 03:57:33 UTC, Timothee Cour via 
Digitalmars-d-learn wrote:
 you can use stuff.canFind(2)

 but sometimes it'd be more convenient to have the other way 
 around (UFCS
 chains etc);

 how about:

 bool isIn(T,T2...)(T needle, T2 haystack)
 if(__traits(compiles,T.init==T2[0].init)){
   foreach(e;haystack){
     if(needle==e) return true;
   }
   return false;
 }
 unittest{
 assert(1.isIn(3,1,2) && !4.isIn(3,1,2));
 }
I like it! I didn't know you could use templates like that! Question though? why doesn't canFind() work on statically allocated arrays? import std.stdio; import std.algorithm; bool contains(T)( T[] haystack,T needle){ foreach(T e;haystack){ if(needle==e) return true; } return false; } unittest{ assert([3,1,2].contains(1) && ![3,1,2].contains(4)); } void main(string[] args) { int[3] stuff=[0,1,2]; if (stuff.contains(2)) { writeln("Hello World!"); } if (stuff.canFind(2)){ // No compile with stuff -> static writeln("This Also WOrks"); } }
 On Mon, Apr 21, 2014 at 8:25 PM, Taylor Hillegeist via 
 Digitalmars-d-learn <
 digitalmars-d-learn puremagic.com> wrote:

 So I find myself Doing this kind of thing very frequently. I 
 have a Array
 of Somethings and i want to see if "something specific" is 
 inside the
 array. I wrote a template for it. but is this the best way to 
 do this kind
 of thing. I feel like it doesn't help with readability. Is 
 there a better
 way? Maybe i missed something in the std library.

 import std.stdio;

 template FNDR(T){
     bool isIn(T Element, T[] Array){
         bool rtn=false;
         foreach(T ArrayElement; Array){
             if(Element==ArrayElement){
                 rtn=true;
             }
         }
     return rtn;
     }
 }

 void main(string[] args)
 {
     int[3] stuff=[0,1,2];
     if (FNDR!int.isIn(2,stuff))
     {
         writeln("Hello World!");
     }
 }


 Is there a way maybe to make it look like this?

 import std.stdio;

 template FNDR(T){
     bool contains(T[] Array,T Element){
         bool rtn=false;
         foreach(T ArrayElement; Array){
             if(Element==ArrayElement){
                 rtn=true;
             }
         }
     return rtn;
     }
 }

 void main(string[] args)
 {
     int[3] stuff=[0,1,2];
     if (stuff.contains(2)) // Much clean! 
 stuff.FNDR!int.contains(2)
 doesn't work
     {
         writeln("Hello World!");
     }
 }

 I'm interested in what you guys think? what is the cleanest 
 way to do this?
Apr 21 2014
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/21/2014 09:22 PM, Taylor Hillegeist wrote:

 Question though? why doesn't canFind() work on statically
 allocated arrays?
That's an issue all of face from time to time. (Happened to me again last week. :) ) The reason is, algorithms like canFind work with input ranges and fixed-length arrays are not input ranges because they cannot support popFront(), which would reduce their length. The solution is to use a full slice of the array by appending [] to it: if (stuff[].canFind(2)) { // <-- note [] It works because now canFind() operates on a temporary slice (aka dynamic array). Getting back to your original question, std.algorithm.find and canFind() are O(N) algorithms, which is too slow if you already have a sorted range. When you indeed have a sorted range, you can pass it through assumeSorted() to create a SortedRange object so that you can take advantage of O(log N) algorithms like trisect() and friends (one of those friends is contains()): import std.range; void main() { auto arr = [ 1, 2, 3, 3, 4, 5 ]; auto result = arr.assumeSorted.trisect(3); assert(result[0].equal([ 1, 2 ])); assert(result[1].equal([ 3, 3 ])); assert(result[2].equal([ 4, 5 ])); } The search in that program is O(log N). Ali
Apr 21 2014
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 21 Apr 2014 23:25:39 -0400, Taylor Hillegeist  
<taylorh140 gmail.com> wrote:

 So I find myself Doing this kind of thing very frequently. I have a  
 Array of Somethings and i want to see if "something specific" is inside  
 the array. I wrote a template for it. but is this the best way to do  
 this kind of thing. I feel like it doesn't help with readability. Is  
 there a better way? Maybe i missed something in the std library.

 import std.stdio;
Change this:
 template FNDR(T){
To this: template isIn(T) {
      bool isIn(T Element, T[] Array){
          bool rtn=false;
          foreach(T ArrayElement; Array){
              if(Element==ArrayElement){
                  rtn=true;
              }
          }
      return rtn;
      }
 }

 void main(string[] args)
 {
      int[3] stuff=[0,1,2];
      if (FNDR!int.isIn(2,stuff))
now: if(isIn(2, stuff)) see implicit function template instantiation (IFTI) in docs. Also, using UFCS (Unified Function Call Syntax (I think)), we can do: if(2.isIn(stuff)) Or if you swap the parameters, and perhaps rename your template/function: if(stuff.contains(2))
      {
          writeln("Hello World!");
      }
 }
-Steve
Apr 22 2014
parent reply " FrankLike" <1150015857 qq.com> writes:
Hi,everyone,
This code must add the 'break',
import std.stdio;
int x=0;
template isin(T){
     bool isin(T[] Array,T Element){
         bool rtn=false;
         foreach(T ArrayElement; Array){
             if(Element==ArrayElement){
                 rtn=true; break;      ← //here add break
             }
          x++;
         }
     return rtn;
     }
}

void main(string[] args)
{
     int[] stuff=[0,1,2,3,4,5,6,7,8,9,10];  ← //here declare int[]

     if (stuff.isin(2)) // Much clean!
     {
		writeln(x);
         writeln("Hello World!");
     }
}
----------------end---------------

Frank
Apr 23 2014
parent " FrankLike" <1150015857 qq.com> writes:
Hi,everyone,
  It works maybe the best:

import std.stdio;

template isin(T){
     bool isin(T[] Array,T Element){
         foreach(T ArrayElement; Array){
             if(Element==ArrayElement){ return true;}
         }
     return false;
     }
}

void main(string[] args)
{
     int[] stuff=[0,1,2,3,4,5,6,7,8,9,10];

     if (stuff.isin(2))
     {
         writeln("Hello World!");
     }

	string[] strs =["Hello","world","hi","Everyone"];
	if(strs.isin("Hi"))
	{
		writeln("find Hi");
	}
	else
	{
		writeln("not find Hi from: "~strs);
	}
}

   ----------------end---------------

   Frank
Apr 23 2014