www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - rectifiedIndexOf()

reply Salih Dincer <salihdb hotmail.com> writes:
It has a traditional very beautiful function:  indexOf() but it 
has an important problem: returns -1 when it can't find 'c'...

```d
void main()
{
   enum chr = 'c';
   auto arr = "dlang".dup;
   if(auto res = arr.indexOf(chr))
   {
     assert(arr[res] == chr);
     // core.exception.ArrayIndexError
   }
}
```

When you try to solve the problem with boolean logic, res is now 
a bool.

```d
void main()
{
   enum chr = 'd';
   auto arr = "dlang".dup;
   if(auto res = arr.indexOf(chr) > -1)
   {
     assert(arr[res] == chr);
     // core.exception.AssertError
   }
}
```

We can solve this problem with an alternativeIndexOf, but we're 
sailing another problem: Rectified Index...

```d
import std.stdio;
void main()
{
   enum chr = 'c';
   auto arr = "dlang".dup;
   if(auto res = arr.rectifiedIndexOf(chr))
   {
     assert(arr[res - 1] == chr);
     res.writefln!"[ --> %s ]";
   } else writeln("Not found!");
}

auto rectifiedIndexOf(A)(A[] arr, A key)
{
   size_t i = 1;
   while(i <= arr.length)
   {
     if(arr[i - 1] == key)
     {
       return i;
     }
     else i++;
   }
   return 0;
}
```

So now that we've broken the traditional index approach, you need 
to consider this (res - 1) in your code.

SDB 79
May 04 2023
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Friday, 5 May 2023 at 00:19:01 UTC, Salih Dincer wrote:
 It has a traditional very beautiful function:  indexOf() but it 
 has an important problem: returns -1 when it can't find 'c'...

 ```d
 void main()
 {
   enum chr = 'c';
   auto arr = "dlang".dup;
   if(auto res = arr.indexOf(chr))
   {
     assert(arr[res] == chr);
     // core.exception.ArrayIndexError
   }
 }
 ```

 When you try to solve the problem with boolean logic, res is 
 now a bool.
 [...]
 So now that we've broken the traditional index approach, you 
 need to consider this (res - 1) in your code.

 SDB 79
As often in D you can use a struct to help: ```d auto toBool(ptrdiff_t t) { struct ToBool { ptrdiff_t value; alias value this; bool opCast(T : bool)() { return value != -1; } } return ToBool(t); } void main() { enum chr = 'l'; auto arr = "dlang".dup; if (auto res = arr.indexOf(chr).toBool()) { assert(res == 1); } } ``` `opCast` is used for the `if` condition and the original value for reading back in the array, via `alias this`.
May 04 2023
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Friday, 5 May 2023 at 02:43:15 UTC, Basile B. wrote:
 As often in D you can use a struct to help...
 `opCast` is used for the `if` condition and the original value 
 for reading back in the array, via `alias this`.
I haven't seen such an accurate solution from those who replied to me until now. Thanks a lot because very works! ```d auto toBool(ptrdiff_t t) { struct ToBool { ptrdiff_t value; alias value this; bool opCast(T : bool)() { return value != -1; } } return ToBool(t); } void find(char chr) { import std.stdio, std.range, std.string : indexOf; if(auto res = arr.indexOf(chr).toBool) { arr.writeln; assert(arr[res] == chr); ' '.repeat(res).writeln("^--found!"); } else { chr.writeln(" character not found!"); } } auto arr = "dlang".dup; void main() { foreach(chr; "cad") chr.find(); } /* Prints: c character not found! dlang ^--found! dlang ^--found! */ ``` SDB 79
May 05 2023
parent reply apz28 <apz28 hotmail.com> writes:
On Friday, 5 May 2023 at 14:50:45 UTC, Salih Dincer wrote:
 On Friday, 5 May 2023 at 02:43:15 UTC, Basile B. wrote:
 As often in D you can use a struct to help...
 `opCast` is used for the `if` condition and the original value 
 for reading back in the array, via `alias this`.
Or as below struct IndexOfResult { ptrdiff_t value; alias value this; bool opCast(T : bool)() const nogc pure safe { return value >= 0; } } void main() { import std.string : indexOf; import std.stdio : writeln, writefln; enum chr = 'a'; enum arr = "dlang"; if (auto res = IndexOfResult(arr.indexOf(chr))) { assert(arr[res] == chr); res.writefln!"[ --> %s ]"; } else writeln("Not found!"); }
May 05 2023
parent Basile B. <b2.temp gmx.com> writes:
On Friday, 5 May 2023 at 16:51:25 UTC, apz28 wrote:
 On Friday, 5 May 2023 at 14:50:45 UTC, Salih Dincer wrote:
 On Friday, 5 May 2023 at 02:43:15 UTC, Basile B. wrote:
 As often in D you can use a struct to help...
 `opCast` is used for the `if` condition and the original 
 value for reading back in the array, via `alias this`.
Or as below struct IndexOfResult { ptrdiff_t value; alias value this; bool opCast(T : bool)() const nogc pure safe { return value >= 0; } } void main() { import std.string : indexOf; import std.stdio : writeln, writefln; enum chr = 'a'; enum arr = "dlang"; if (auto res = IndexOfResult(arr.indexOf(chr))) { assert(arr[res] == chr); res.writefln!"[ --> %s ]"; } else writeln("Not found!"); }
Yeah IndexOfResult is a much better name... but you should not change the comparison operator... in theory using `!=-1` allows `-2`, ie `size_t.max-1` to be a valid result.
May 05 2023
prev sibling next sibling parent apz28 <apz28 hotmail.com> writes:
On Friday, 5 May 2023 at 00:19:01 UTC, Salih Dincer wrote:
 It has a traditional very beautiful function:  indexOf() but it 
 has an important problem: returns -1 when it can't find 'c'...

 ```d
 void main()
 {
   enum chr = 'c';
   auto arr = "dlang".dup;
   if(auto res = arr.indexOf(chr))
   {
     assert(arr[res] == chr);
     // core.exception.ArrayIndexError
   }
 }
 ```

 When you try to solve the problem with boolean logic, res is 
 now a bool.

 ```d
 void main()
 {
   enum chr = 'd';
   auto arr = "dlang".dup;
   if(auto res = arr.indexOf(chr) > -1)
   {
     assert(arr[res] == chr);
     // core.exception.AssertError
   }
 }
 ```
Try below https://gist.github.com/run-dlang/316a1b9df1c14dade4c5ff13c927cc84
May 05 2023
prev sibling parent reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Friday, 5 May 2023 at 00:19:01 UTC, Salih Dincer wrote:
 It has a traditional very beautiful function: indexOf() but it 
 has an important problem: returns -1 when it can't find 'c'...
That is bad design. It should return an optional type or something like that, but D doesn’t have those. C++ has a lot of similar functions and I guess that was one reason why C++17 introduced an *init-statment* to `if`. D could do the same. ```d if (auto index = arr.indexOf('c'); index >= 0) … ```
May 06 2023
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 6 May 2023 at 16:39:13 UTC, Quirin Schroll wrote:
 On Friday, 5 May 2023 at 00:19:01 UTC, Salih Dincer wrote:
 It has a traditional very beautiful function: indexOf() but it 
 has an important problem: returns -1 when it can't find 'c'...
That is bad design. It should return an optional type or something like that, but D doesn’t have those. C++ has a lot of similar functions and I guess that was one reason why C++17 introduced an *init-statment* to `if`. D could do the same. ```d if (auto index = arr.indexOf('c'); index >= 0) … ```
In fact, there is worse! The intent is to prevent leaking outside the scope of if-else. But it doesn't work in the else block and we get the error undefined identifier `num`. ```d if(auto num = imported!"std.random".uniform!int.max % 2)  {    assert(num > 0);  } else {    //assert(num == 0);  } ``` I would like these issues to be resolved, but we spend our energy on more difficult things! SDB 79
May 06 2023
parent Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Saturday, 6 May 2023 at 18:58:54 UTC, Salih Dincer wrote:
 On Saturday, 6 May 2023 at 16:39:13 UTC, Quirin Schroll wrote:
 On Friday, 5 May 2023 at 00:19:01 UTC, Salih Dincer wrote:
 It has a traditional very beautiful function: indexOf() but 
 it has an important problem: returns -1 when it can't find 
 'c'...
That is bad design. It should return an optional type or something like that, but D doesn’t have those. C++ has a lot of similar functions and I guess that was one reason why C++17 introduced an *init-statment* to `if`. D could do the same. ```d if (auto index = arr.indexOf('c'); index >= 0) … ```
In fact, there is worse! The intent is to prevent leaking outside the scope of if-else. But it doesn't work in the else block and we get the error undefined identifier `num`. ```d if(auto num = imported!"std.random".uniform!int.max % 2)  {    assert(num > 0);  } else {    //assert(num == 0);  } ``` I would like these issues to be resolved, but we spend our energy on more difficult things!
I guess the reason why something that is declared in the condition is scoped to the “then” part and not visible in the “else” part is that if something evaluates to `false`, usually it’s not interesting. Something that evaluates to `false` is a `bool` that’s `false`, a number that’s `0`, or a pointer or class handle or whatever reference type that holds no interesting state. A user-defined type evaluates to `false` and has an interesting value is really bad design. However, if you do C++’s `if` with initialization and condition separately, you can handle the “uninteresting `false`” value in the “then” branch and do the interesting work in the “else” branch. For that reason, something declared in the *init-statement* of an `if` should be visible in the “else” branch.
May 12 2023