Thread overview
rotate left an array
Oct 03, 2022
Fausto
Oct 03, 2022
Nick Treleaven
Oct 03, 2022
Andrey Zherikov
Oct 03, 2022
Ali Çehreli
Oct 04, 2022
Paul Backus
Oct 04, 2022
Ali Çehreli
Oct 04, 2022
Paul Backus
Oct 04, 2022
H. S. Teoh
Oct 04, 2022
rassoc
Oct 04, 2022
Christian Köstlin
October 03, 2022

Hello all,

I am trying to rotate left an array.
I found a very basic way, and I am not sure if there is something clever than this :) maybe using slices...
the external for represents how many times you are rotating (in this case 2).

void main()
{
    import std.range;
    import std.stdio: write, writeln, writef, writefln;

    int[] arr1 = [ 1, 2, 3, 4 ];
    int t = 0;

    writeln(arr1);

    for (int j = 0;j<2;j++) {
    t = arr1[0];
    for(int i = 0;i<arr1.length-1;i++) {
        arr1[i] =  arr1[i+1];
    }
    arr1[$-1] = t;
    }

    writeln(arr1);

}

thanks a lot
Fausto

October 03, 2022

On Monday, 3 October 2022 at 18:09:05 UTC, Fausto wrote:

>

Hello all,

I am trying to rotate left an array.
I found a very basic way, and I am not sure if there is something clever than this :) maybe using slices...

Here we can't use slice assignment instead of the inner loop because that doesn't work for an overlapping slice. (Instead there's copy in std.algorithm).

The algorithm you wrote doesn't scale the best for speed - yours is the second one mentioned here:
https://www.geeksforgeeks.org/array-rotation/

Phobos has bringToFront(arr[0..2], arr[2..$]) which does the same thing as a rotate(arr, 2) function. It seems to use the third algorithm from the link (or at least has the same time and space complexity).

The first algorithm may also work better in some cases, when swapping is expensive or when the result is duplicated anyway.

October 03, 2022

On Monday, 3 October 2022 at 18:09:05 UTC, Fausto wrote:

>

Hello all,

I am trying to rotate left an array.
I found a very basic way, and I am not sure if there is something clever than this :) maybe using slices...
the external for represents how many times you are rotating (in this case 2).

If you don't need to add or remove the data from your array then I'd go with constant array and translating external index to an internal one for this array. So it's gonna be something like a "rotated view".

October 03, 2022
On 10/3/22 13:48, Andrey Zherikov wrote:
> a "rotated view".

Without indexes:

import std.range : empty;

auto rotatedView(R)(R range)
in (!range.empty)
{
    import std.range : chain, front, only, popFront;
    const fr = range.front;
    range.popFront();
    return chain(range, only(fr));
}

void main()
{
    import std.algorithm : equal;
    int[] arr1 = [ 1, 2, 3, 4 ];
    assert(arr1.rotatedView.equal([ 2, 3, 4, 1 ]));

    // Now this is getting a little expensive! :)
    assert(arr1
           .rotatedView
           .rotatedView
           .equal([ 3, 4, 1, 2 ]));
}

Ali


October 04, 2022
On Monday, 3 October 2022 at 21:06:36 UTC, Ali Çehreli wrote:
> On 10/3/22 13:48, Andrey Zherikov wrote:
>> a "rotated view".
>
> Without indexes:
>
> import std.range : empty;
>
> auto rotatedView(R)(R range)
> in (!range.empty)
> {
>     import std.range : chain, front, only, popFront;
>     const fr = range.front;
>     range.popFront();
>     return chain(range, only(fr));
> }

Tiny nitpick: this should use

    const fr = range.save.front;

...to ensure that `fr` is not invaliated or overwritten by the subsequent call to range.popFront (e.g., think of File.byLine here).
October 03, 2022
On 10/3/22 17:00, Paul Backus wrote:
> On Monday, 3 October 2022 at 21:06:36 UTC, Ali Çehreli wrote:
>> On 10/3/22 13:48, Andrey Zherikov wrote:
>>> a "rotated view".
>>
>> Without indexes:
>>
>> import std.range : empty;
>>
>> auto rotatedView(R)(R range)
>> in (!range.empty)
>> {
>>     import std.range : chain, front, only, popFront;
>>     const fr = range.front;
>>     range.popFront();
>>     return chain(range, only(fr));
>> }
>
> Tiny nitpick: this should use
>
>      const fr = range.save.front;
>
> ...to ensure that `fr` is not invaliated or overwritten by the
> subsequent call to range.popFront (e.g., think of File.byLine here).

Good catch but I think what we want is a copy of the front element, at least for InputRanges (.save does not work for File.byLine :/).

What is the generic way of copying an element? I wonder whether we have to use isSomeString to take care of all element types.

Ali


October 04, 2022
On 10/3/22 23:06, Ali Çehreli via Digitalmars-d-learn wrote:
> auto rotatedView(R)(R range)

Or even more generic by chaining two slices in case the range permits it:

auto rotatedView(R)(R range, long n = 1)
if (...)
{
	if (n == 0) return range;
	...
	n %= range.length;
	...
	return chain(slice1, slice2);
}

Used something like that in previous advent of code challenges where they expect you to go for doubly linked lists due to large buffer size.
October 04, 2022
On Tuesday, 4 October 2022 at 00:38:25 UTC, Ali Çehreli wrote:
> Good catch but I think what we want is a copy of the front element, at least for InputRanges (.save does not work for File.byLine :/).
>
> What is the generic way of copying an element? I wonder whether we have to use isSomeString to take care of all element types.

AFAIK there is no generic way to perform a deep copy of an arbitrary value in D. You could write a function to do it for all built-in types, but you might still run into trouble with user-defined types (e.g., how do you deep-copy a RefCounted!T without any knowledge of its specific semantics?).

I guess you could use a hybrid approach; e.g.,

    static if (isDeepCopyable!(ElementType!R))
        auto fr = range.front.deepCopy;
    else
        auto fr = range.front.save;

This would make it possible to accommodate some pure input ranges (including File.byLine), but would still require a forward range in the general case.
October 03, 2022
On Mon, Oct 03, 2022 at 05:38:25PM -0700, Ali Çehreli via Digitalmars-d-learn wrote: [...]
> Good catch but I think what we want is a copy of the front element, at least for InputRanges (.save does not work for File.byLine :/).

One of the things we need to settle in Phobos v2 is what to do with transient ranges like File.byLine (i.e., ranges whose .front value is invalidated by .popFront).  When you don't need to access each line after calling .popFront, .byLine's current implementation reduces allocations and decreases GC pressure.  However, when you do need to save it, it produces counterintuitive results, like here.


> What is the generic way of copying an element? I wonder whether we have to use isSomeString to take care of all element types.
[...]

This was discussed many years ago.  There is no generic way to copy an element, because there is no language-wide .clone method that enforces the right semantics for every type.  You cannot simply deep-copy something, as might be a tempting solution at first glance, because you cannot tell, for an arbitary type, whether a reference member is meant to be an owning reference (the referent needs to be cloned) or a non-owning reference (the referent should not be cloned).  Both are valid use cases, and there is no way to distinguish between them without contextual knowledge of the type.

For example, if your range is generating, say, a tree of objects each time .popFront is called, then you probably want to deep-copy the object tree when you're saving the element.  However, if the range is iterating over, say, some nodes in a preexisting graph, then you probably *don't* want to be duplicating graph nodes when you save the value of .front, because in this case .front merely references these nodes, it doesn't own them.  Without application-specific knowledge, you can't tell which of these cases you're dealing with.


T

-- 
Customer support: the art of getting your clients to pay for your own incompetence.
October 04, 2022
If you are ok with using things from std.range you could use something like this:


```d
import std.range : cycle, drop, take;
import std.stdio : writeln;

int main(string[] args)
{
    auto r = [1, 2, 3, 4, 5, 6, 7, 8];
    writeln(r.cycle.drop(3).take(r.length));
    return 0;
}
```

Kind regards,
Christian