www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - 'in' for arrays?

reply Bill Baxter <dnewsgroup billbaxter.com> writes:
I keep wanting to say
   if (val in somearray) {
   }

but 'in' doesn't work for arrays...  Is there any reason why not?
Basically I just expect it to do something like this function (untested, 
modified from a similar function in Cashew):

T* item_in (T) (T[] haystack, T cmp)
{
   foreach (index, inout needle; haystack) {
     if (needle==cmp) {
       return &needle;
     }
   }
   return null;
}

I.e. I just expect it to do a plain old linear search through the list, 
nothing fancy, but it would be handy.

--bb
Dec 05 2006
next sibling parent Lionello Lunesu <lio lunesu.remove.com> writes:
Bill Baxter wrote:
 I keep wanting to say
   if (val in somearray) {
   }

It makes sense to make "in" behave as if an int[] is a int[int], but the problem is that "in" for normal arrays is O(n), slow. If you need to search the array, you probably should have been using another container in the first place. My philosophy is always that CPU-expensive actions should also appear as such in code. A small "in" that actual does a linear search might seem a like a good idea, but people should be discouraged from using it. L.
Dec 06 2006
prev sibling next sibling parent reply Egor Starostin <egorst gmail.com> writes:
 I keep wanting to say
    if (val in somearray) {
    }

For example, in Python I can write if val in ('off','disable','no') and in D I have to write if (val == "off" || val == "disable" || val == "no") which is less readable (to me, at least). -- Egor
Dec 06 2006
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Egor Starostin wrote:
 I keep wanting to say
    if (val in somearray) {
    }

For example, in Python I can write if val in ('off','disable','no') and in D I have to write if (val == "off" || val == "disable" || val == "no") which is less readable (to me, at least). -- Egor

Yep. That's the kind of usage case I have in mind. About "it's expensive but it doesn't look expensive"... Expensive is all relative. If you tend to have lists with tens or even hundreds of elements in them then a linear search is a perfectly reasonable way to do it. And in terms of "looks inexpensive", well to me (val in somearray) looks exactly like it's going to do a linear search. What else *could* it do when handed a general array? --bb
Dec 06 2006
prev sibling next sibling parent reply Lionello Lunesu <lio lunesu.remove.com> writes:
Egor Starostin wrote:
 I keep wanting to say
    if (val in somearray) {
    }

For example, in Python I can write if val in ('off','disable','no')

OK, granted, if (val in ["off","disable","no"]) does look cool, but a switch(val) would still be faster (uses binary search if I'm not mistaken). Maybe D should get an alternative "if" for this construct: switch(val) { case "off","disable","no": // code here default: break; } Anyway, supporting "in" for normal arrays has my vote. In my post I just mentioned a possible concern. L.
Dec 06 2006
parent reply Alexander Panek <a.panek brainsware.org> writes:
Lionello Lunesu wrote:
 Egor Starostin wrote:
 I keep wanting to say
    if (val in somearray) {
    }

For example, in Python I can write if val in ('off','disable','no')

OK, granted, if (val in ["off","disable","no"]) does look cool, but a switch(val) would still be faster (uses binary search if I'm not mistaken). Maybe D should get an alternative "if" for this construct: switch(val) { case "off","disable","no": // code here default: break; }

switch ( val ) { case "off": case "disable": case "no": // code here break; } ?
 
 Anyway, supporting "in" for normal arrays has my vote. In my post I just 
 mentioned a possible concern.
 
 L.

Kind regards, Alex
Dec 06 2006
parent reply Lionello Lunesu <lio lunesu.remove.com> writes:
Alexander Panek wrote:
 Lionello Lunesu wrote:
 switch(val) {
   case "off","disable","no":
      // code here
   default:
      break;
 }

switch ( val ) { case "off": case "disable": case "no": // code here break; }

case x,y: is the same as case x: case y: Apart from that, if you don't provide a 'default' statement, D inserts one with assert(0), meaning that your code would trip if val were anything other than those 3 mentioned cases. L.
Dec 06 2006
parent reply Alexander Panek <a.panek brainsware.org> writes:
Lionello Lunesu wrote:
 Alexander Panek wrote:
 Lionello Lunesu wrote:
 switch(val) {
   case "off","disable","no":
      // code here
   default:
      break;
 }

switch ( val ) { case "off": case "disable": case "no": // code here break; }

case x,y: is the same as case x: case y: Apart from that, if you don't provide a 'default' statement, D inserts one with assert(0), meaning that your code would trip if val were anything other than those 3 mentioned cases. L.

Yea..I've seen that I forgot the default: break; after replying.. :P
Dec 06 2006
parent reply Hasan Aljudy <hasan.aljudy gmail.com> writes:
Alexander Panek wrote:
 Lionello Lunesu wrote:
 Alexander Panek wrote:
 Lionello Lunesu wrote:
 switch(val) {
   case "off","disable","no":
      // code here
   default:
      break;
 }

switch ( val ) { case "off": case "disable": case "no": // code here break; }

case x,y: is the same as case x: case y: Apart from that, if you don't provide a 'default' statement, D inserts one with assert(0), meaning that your code would trip if val were anything other than those 3 mentioned cases. L.

Yea..I've seen that I forgot the default: break; after replying.. :P

And you're very likely to forget it when writing code ..
Dec 06 2006
parent Alexander Panek <a.panek brainsware.org> writes:
Hasan Aljudy wrote:
 
 
 Alexander Panek wrote:
 Lionello Lunesu wrote:
 Alexander Panek wrote:
 Lionello Lunesu wrote:
 switch(val) {
   case "off","disable","no":
      // code here
   default:
      break;
 }

switch ( val ) { case "off": case "disable": case "no": // code here break; }

case x,y: is the same as case x: case y: Apart from that, if you don't provide a 'default' statement, D inserts one with assert(0), meaning that your code would trip if val were anything other than those 3 mentioned cases. L.

Yea..I've seen that I forgot the default: break; after replying.. :P

And you're very likely to forget it when writing code ..

I usually don't forget it..actually. But that's just me. ;) (In this case lack of time prevented any re-reading :O )
Dec 06 2006
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Egor Starostin" <egorst gmail.com> wrote in message 
news:el5vpc$9nt$1 digitaldaemon.com...
 Me too.

 For example, in Python I can write

 if val in ('off','disable','no')

 and in D I have to write

 if (val == "off" || val == "disable" || val == "no")

 which is less readable (to me, at least).

struct _Tuple(T...) { bool opIn_r(U)(U value) { foreach(val; T) { static if(is(typeof(val) : U)) { if(val == value) return true; } } return false; } } template Tuple(T...) { const _Tuple!(T) Tuple; } void main() { if(4 in Tuple!("hi", 5.5, 4)) writefln("yep"); else writefln("nope"); if("no" in Tuple!("hi", 5.5, 4)) writefln("yep"); else writefln("nope"); } Meh. :)
Dec 06 2006
next sibling parent Alexander Panek <a.panek brainsware.org> writes:
Ha! Very nice.

I start to like those mysterious Tuples. ;)

Jarrett Billingsley wrote:
 "Egor Starostin" <egorst gmail.com> wrote in message 
 news:el5vpc$9nt$1 digitaldaemon.com...
 Me too.

 For example, in Python I can write

 if val in ('off','disable','no')

 and in D I have to write

 if (val == "off" || val == "disable" || val == "no")

 which is less readable (to me, at least).

struct _Tuple(T...) { bool opIn_r(U)(U value) { foreach(val; T) { static if(is(typeof(val) : U)) { if(val == value) return true; } } return false; } } template Tuple(T...) { const _Tuple!(T) Tuple; } void main() { if(4 in Tuple!("hi", 5.5, 4)) writefln("yep"); else writefln("nope"); if("no" in Tuple!("hi", 5.5, 4)) writefln("yep"); else writefln("nope"); } Meh. :)

Dec 06 2006
prev sibling parent Pragma <ericanderton yahoo.removeme.com> writes:
Tuples, For The Win.

This is a prime example of why we can overload operators in D, and how 
templates further enhance that capability.  There's little need to add 
language features when the language supports so many possible constructs 
already.

Jarrett Billingsley wrote:
 struct _Tuple(T...)
 {
  bool opIn_r(U)(U value)
  {
   foreach(val; T)
   {
    static if(is(typeof(val) : U))
    {
     if(val == value)
      return true;
    }
   }
 
   return false;
  }
 }
 
 template Tuple(T...)
 {
  const _Tuple!(T) Tuple;
 }
 
 void main()
 {
  if(4 in Tuple!("hi", 5.5, 4))
   writefln("yep");
  else
   writefln("nope");
 
  if("no" in Tuple!("hi", 5.5, 4))
   writefln("yep");
  else
   writefln("nope");
 }
 
 
 Meh.  :) 
 
 

-- - EricAnderton at yahoo
Dec 07 2006
prev sibling next sibling parent reply Lionello Lunesu <lio lunesu.remove.com> writes:
Bill Baxter wrote:
 I keep wanting to say
   if (val in somearray) {
   }

Wait! That's just it! It's "KEY in CONTAINER" and the KEY of a regular array is the index, not the value. So dare I suggest the following instead? if (index in somearray) { } This "in" would be: (cast(size_t)index < somearray.length?&somearray[index]:null) Totally analogous to the associative array. And it also solves the "Length comparison" issue. L.
Dec 06 2006
next sibling parent Chad J <gamerChad _spamIsBad_gmail.com> writes:
Lionello Lunesu wrote:
 Bill Baxter wrote:
 
 I keep wanting to say
   if (val in somearray) {
   }

Wait! That's just it! It's "KEY in CONTAINER" and the KEY of a regular array is the index, not the value. So dare I suggest the following instead? if (index in somearray) { } This "in" would be: (cast(size_t)index < somearray.length?&somearray[index]:null) Totally analogous to the associative array. And it also solves the "Length comparison" issue. L.

hmmm, seems unintuitive to me. I tend to think of the "in" operator acting on a set and a potential member of the set. I also tend to think of an array as a set of somethings. Now when I make an int[] and say something like if( 14 in somethings ) I'd expect it to look through the set of somethings and see if the number 14 is in there. I wouldn't expect it to look through the set of integers that are less than somethings.length to see if 14 is in that. Now I'm wondering, why is it a good idea to have "in" mean what it does for aa's? It seems to hold back a lot of other stuff, and not provide much. It would be nice to be able to write foreach(value in array) instead of using the strange semicolon syntax - and this is very common. I doubt the current usage of "in" is anywhere near as common as that, or even as common as something like if(ipAddy in ipAddresses). Thus it would be more appropriate to, in those few cases of aa "in" usage, instead write aa.hasKey(key) instead of (key in aa). Changing that would also allow you to write (value in aa). Notice that associative arrays have a .keys property. Perhaps then, we could simply define the current usage of "in" - (key in aa) - to be shorthand for (key in aa.keys). With that "in" has a more intuitive meaning, IMO.
Dec 06 2006
prev sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Lionello Lunesu wrote:
 Bill Baxter wrote:
 I keep wanting to say
   if (val in somearray) {
   }

Wait! That's just it! It's "KEY in CONTAINER" and the KEY of a regular array is the index, not the value. So dare I suggest the following instead? if (index in somearray) { } This "in" would be: (cast(size_t)index < somearray.length?&somearray[index]:null) Totally analogous to the associative array. And it also solves the "Length comparison" issue. L.

Now this I actually like... Can already think of places I could use it, such as in Bovis during symbol/id lookups. Its a nice idea. (Might just add it to Cashew in the meantime.) -- Chris Nicholson-Sauls
Dec 06 2006
parent Bill Baxter <wbaxter gmail.com> writes:
Chris Nicholson-Sauls wrote:
 Lionello Lunesu wrote:
 
 Bill Baxter wrote:

 I keep wanting to say
   if (val in somearray) {
   }

Wait! That's just it! It's "KEY in CONTAINER" and the KEY of a regular array is the index, not the value. So dare I suggest the following instead? if (index in somearray) { } This "in" would be: (cast(size_t)index < somearray.length?&somearray[index]:null) Totally analogous to the associative array. And it also solves the "Length comparison" issue. L.

Now this I actually like... Can already think of places I could use it, such as in Bovis during symbol/id lookups. Its a nice idea. (Might just add it to Cashew in the meantime.) -- Chris Nicholson-Sauls

Ugh. I've created a monster. That would make sense in Lua where there is only one data structure (table), which can be indexed with numbers or non-numbers equally well, but in D, it just doesn't seem right to say 2 is 'in' ["spam","eggs","spam"]. I certainly don't see any 2 in there. The operation you want seems more like a get(): T* get(T[] arr, size_t index) { return (index < arr.length ? &arr[index] : null) } if (somearray.get(10)) { } The dict type in Python uses something like that for safe indexing, otherwise you use [] if throwing an exception is ok. --bb
Dec 06 2006
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Bill Baxter wrote:
 I keep wanting to say
   if (val in somearray) {
   }
 
 but 'in' doesn't work for arrays...  Is there any reason why not?

You appear to be wanting it to find a given _value_ in an array. Several people have requested this. The problem is that it would create a confusing inconsistency with associative arrays, in which it is defined to find a given _key_. Logically, if in does anything on linear arrays, then it should check whether the given index is within the array's bounds. This isn't just purism - it's also a generic programming concern. Moreover, if we were to define an operator that finds a given _value_ in a linear array, we ought to have it for AAs too. Stewart.
Dec 07 2006
next sibling parent Derek Parnell <derek nomail.afraid.org> writes:
On Thu, 07 Dec 2006 22:26:15 +0000, Stewart Gordon wrote:

Is this useful to someone?

// -----------------
template ContainsFrom (T)
{
    // Return 'index' if 'element' found in 'array' otherwise return -1
    int ContainsFrom(T[] pArray, T pElement, int pIndex)
    {
        if (pIndex >= 0)
        {
            while (pIndex < pArray.length)
            {
                if (pElement == pArray[pIndex])
                    return pIndex;
                pIndex++;
            }
        }
        return -1; // Not Found
    }
}

template Contains (T)
{
    int Contains(T[] pArray, T pElement)
    {
        return ContainsFrom(pArray,pElement,0);
    }

}

unittest
{

   int[] X;
   X ~= 3;
   X ~= 2;
   X ~= 6;
   X ~= 8;
   X ~= 1;

   assert(X.Contains(8)  == 3);
   assert(X.Contains(3)  == 0);
   assert(X.Contains(-1) == -1);
   assert(X.Contains(99) == -1);
   assert(X.ContainsFrom(8,4)  == -1);
   assert(X.ContainsFrom(8,2)  == 3);


   char[] Y = "qwerty";

   assert(Y.Contains('a') == -1);
   assert(Y.Contains('q') == 0);
   assert(Y.Contains('t') == 4);
   assert(Y.Contains('z') == -1);

}

// -------------


-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocrity!"
8/12/2006 9:52:26 AM
Dec 07 2006
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Stewart Gordon wrote:
 Bill Baxter wrote:
 I keep wanting to say
   if (val in somearray) {
   }

 but 'in' doesn't work for arrays...  Is there any reason why not?

You appear to be wanting it to find a given _value_ in an array. Several people have requested this. The problem is that it would create a confusing inconsistency with associative arrays, in which it is defined to find a given _key_.

Confusing to whom? That's the way it works in Python, and it never seemed the least bit odd or confusing to me, nor dare I say to the vast majority of Python users. If you want to check for a value in an AA all you would need is "v in aa.values". There's no need for a special 'check values' function.
 Logically, if in does anything on linear arrays, then it should check 
 whether the given index is within the array's bounds. This isn't just
 purism - it's also a generic programming concern.

Depends on how you think of an array. Technically, yes, that's logical if you think of an array as a function that maps natural numbers to values (which is the functional purist's view). But in terms of usage, for the most part arrays tend to be more like generic containers for (ordered) values, stored adjacent to each other in memory because that's the most efficient for certain applications. The fact that I access an element by an index is just a side effect of that. In fact sometimes I don't use indices, I use pointers instead. Should 'x in array' check if the pointer value x is array's memory range? Arrays, linked lists, sets -- for a lot of purposes they are basically interchangeable. They're all just containers that hold values. Which one you choose just depends on what operations on those values need to be fast for your application, and what sort of ordering matters to you. In my experience it's much more common to start with an array then realize at some point that insertion matters to me more than random access, so I switch to a linked list. In that case should 'x in container' change from querying if the index is in the container to querying if the value is in the container (which is the only logical thing for 'in' to do on a linked list)? Seems 'generic programming concerns' in that case would be better served by having 'in' check values. For practical purposes, arrays, lists, and sets are much more similar to each other than arrays and associative arrays. So if there is any 'generic programming concern' it should default to making the lists/array/set types be generically interchangeable, not arrays and associative arrays. And that's all I'm gonna say about it. There's reasonable arguments both ways and neither argument amounts to a hill of beans if Walter isn't interested. --bb
Dec 07 2006