Thread overview
Can you simplify nested Indexed types?
Dec 27, 2022
Sergei Nosov
Dec 27, 2022
Salih Dincer
Dec 27, 2022
Sergei Nosov
Dec 27, 2022
Salih Dincer
Dec 27, 2022
Salih Dincer
Dec 27, 2022
Ali Çehreli
Dec 28, 2022
Sergei Nosov
Dec 28, 2022
Tejas
December 27, 2022

Consider, I have the following code:

    auto a = [3, 6, 2, 1, 5, 4, 0];

    auto indicies = iota(3);
    auto ai = indexed(a, indicies);
    ai = indexed(ai, iota(2));

    writeln(ai);

Basically, my idea is to apply indexed to an array several times and have all the intermediaries saved in the same variable. The provided code doesn't compile with an error:

Error: cannot implicitly convert expression `indexed(ai, iota(2))` of type `Indexed!(Indexed!(int[], Result), Result)` to `Indexed!(int[], Result)`

I wonder, if there's a way to "collapse" or "simplify" the Indexed!(Indexed!(int[], Result), Result) type to just Indexed!(int[], Result) ?

December 27, 2022

On Tuesday, 27 December 2022 at 15:09:11 UTC, Sergei Nosov wrote:

>

Consider, I have the following code:

    auto a = [3, 6, 2, 1, 5, 4, 0];

    auto indicies = iota(3);
    auto ai = indexed(a, indicies);
    //ai = indexed(ai, iota(2));

    writeln(ai);

I confuse about comment line that I mark...

SDB@79

December 27, 2022

On Tuesday, 27 December 2022 at 15:20:24 UTC, Salih Dincer wrote:

>

On Tuesday, 27 December 2022 at 15:09:11 UTC, Sergei Nosov wrote:

>

Consider, I have the following code:

    auto a = [3, 6, 2, 1, 5, 4, 0];

    auto indicies = iota(3);
    auto ai = indexed(a, indicies);
    //ai = indexed(ai, iota(2));

    writeln(ai);

I confuse about comment line that I mark...

SDB@79

Not sure I'll be more helpful, but I'll try to add more details.

I have an array and I use indexed on it. Conceptually, I now have a second array, but it doesn't exist in memory explicitly - only a function to map indicies from "second array" to "first array" is stored; all the values are stored once - in the "first array".

Now, I want to have third array that will do the same trick with the second array. The problem is that the second array is not really an array (but, conceptually, it is an array with random access). If I create a new variable with auto as type - obviously, it works. But can I use the same variable I used to store the "second array"? (In the provided code that doesn't work because of the type mismatch).

December 27, 2022

On 12/27/22 10:31 AM, Sergei Nosov wrote:

>

On Tuesday, 27 December 2022 at 15:20:24 UTC, Salih Dincer wrote:

>

On Tuesday, 27 December 2022 at 15:09:11 UTC, Sergei Nosov wrote:

>

Consider, I have the following code:

    auto a = [3, 6, 2, 1, 5, 4, 0];

    auto indicies = iota(3);
    auto ai = indexed(a, indicies);
    //ai = indexed(ai, iota(2));

    writeln(ai);

I confuse about comment line that I mark...

SDB@79

Not sure I'll be more helpful, but I'll try to add more details.

I have an array and I use indexed on it. Conceptually, I now have a second array, but it doesn't exist in memory explicitly - only a function to map indicies from "second array" to "first array" is stored; all the values are stored once - in the "first array".

Now, I want to have third array that will do the same trick with the second array. The problem is that the second array is not really an array (but, conceptually, it is an array with random access). If I create a new variable with auto as type - obviously, it works. But can I use the same variable I used to store the "second array"? (In the provided code that doesn't work because of the type mismatch).

So the short answer is no.

The long of it is that Indexed is using a source range to give it indexes. In order to save it as the same type, you need to resolve the source of the indexes, when indiexed with the new source range, into the same type, which is not something the library can do. It would have to be specialized to recognize it's using iota as the index range, and then transform the iotas into one iota call. Which isn't impossible, but would be something specialized to this problem.

What could be an answer is to have a function that takes 2 iotas, and provides the values as if you were applying the indexes of one to the other, something like:

iota!T translate(T)(iota!T orig, iota!T mapping)
{
   // you write this part
}

Then you can possibly define a function that can convert it properly.

-Steve

December 27, 2022

On Tuesday, 27 December 2022 at 15:09:11 UTC, Sergei Nosov wrote:

>

Consider, I have the following code:

    auto a = [3, 6, 2, 1, 5, 4, 0];

    auto indicies = iota(3);
    auto ai = indexed(a, indicies);
    ai = indexed(ai, iota(2));

    writeln(ai);

Why not use filter(), isn't it important to filter out what's in range?

import std.algorithm;
import std.stdio;
import std.range;

int[] a = [3, 6, 2, 1, 5, 4, 0];
auto indicies = iota(3);
auto ai = a.filter!(e => e >= indicies.front
                      && e <= indicies.back);
ai.writeln; // [2, 1, 0]

SDB@79

December 27, 2022
On 12/27/22 07:09, Sergei Nosov wrote:

> Basically, my idea is to apply `indexed` to an array several times and
> have all the intermediaries saved in the same variable.

There may be other ways of achieving the same goal without assigning to the same variable.

> I wonder, if there's a way to "collapse" or "simplify" the
> `Indexed!(Indexed!(int[], Result), Result)` type to just
> `Indexed!(int[], Result)` ?

If what you are looking for is a way of defining a variable for "any InputRange that produces a specific type (size_t in this case)", then there is inputRangeObject, which uses OOP:

  https://dlang.org/phobos/std_range_interfaces.html#InputRange

I have an additional example here:


http://ddili.org/ders/d.en/ranges_more.html#ix_ranges_more.inputRangeObject

Ali

December 27, 2022

On Tuesday, 27 December 2022 at 16:40:31 UTC, Salih Dincer wrote:

>
import std.algorithm;
import std.stdio;
import std.range;

int[] a = [3, 6, 2, 1, 5, 4, 0];
auto indicies = iota(3);
auto ai = a.filter!(e => e >= indicies.front
                      && e <= indicies.back);
ai.writeln; // [2, 1, 0]

Or?

  indicies.each!((i) => a[i].write(" "));
  writeln(); // 3 6 2

SDB@79

December 28, 2022

On Tuesday, 27 December 2022 at 15:09:11 UTC, Sergei Nosov wrote:

>

Consider, I have the following code:

    auto a = [3, 6, 2, 1, 5, 4, 0];

    auto indicies = iota(3);
    auto ai = indexed(a, indicies);
    ai = indexed(ai, iota(2));

    writeln(ai);

Basically, my idea is to apply indexed to an array several times and have all the intermediaries saved in the same variable. The provided code doesn't compile with an error:

Error: cannot implicitly convert expression `indexed(ai, iota(2))` of type `Indexed!(Indexed!(int[], Result), Result)` to `Indexed!(int[], Result)`

I wonder, if there's a way to "collapse" or "simplify" the Indexed!(Indexed!(int[], Result), Result) type to just Indexed!(int[], Result) ?

Well, pretty sure this isn't what you meant by "same variable" but since it technically does what you want, I decided to share it: Basically I'm abusing array and this thing might be pretty memory heavy...

import std;

void main()
{

    auto a = [3, 6, 2, 1, 5, 4, 0];

    auto indices = iota(3);
    auto ai = indexed(a, indices).array;
    ai = indexed(ai, iota(2)).array;

    writeln(ai); // [3, 6]
}
December 28, 2022

On Tuesday, 27 December 2022 at 16:43:49 UTC, Ali Çehreli wrote:

>

On 12/27/22 07:09, Sergei Nosov wrote:
If what you are looking for is a way of defining a variable for "any InputRange that produces a specific type (size_t in this case)", then there is inputRangeObject, which uses OOP:

https://dlang.org/phobos/std_range_interfaces.html#InputRange

I have an additional example here:

http://ddili.org/ders/d.en/ranges_more.html#ix_ranges_more.inputRangeObject

Ali

Thanks, everyone!

I guess, this answer is the closest to what I was looking for. Somehow, I missed the range interfaces (and was considering to use Variant or smth). It does seem to answer the original question, albeit with layer(s) of indirection.

  auto indicies = iota(3);
  RandomAccessFinite!int ai = indexed(a, indicies).inputRangeObject;
  ai = indexed(ai, iota(2)).inputRangeObject;

Still, my gut feel is that some compile-time solution is possible - will, probably, tinker with it for a little more.

>

Why not use filter(), isn't it important to filter out what's in range?

That does something different.

>

Well, pretty sure this isn't what you meant by "same variable" but since it technically does what you want, I decided to share it: Basically I'm abusing array and this thing might be pretty memory heavy...

Yeah, using arrays is another alternative, but as you mention, it uses more memory and makes index evaluation eager (vs lazy).