g | x | w | all
Bytes Lang Time Link
032Pip xp210815T205457ZDLosc
039BQN210914T070059Zfrasiyav
146jq210913T205918ZMichael
131C gcc210818T054501Zatt
023Husk210816T232306ZDominic
099R210816T200456Zpajonk
022Jelly210816T232807ZJonathan
145PowerShell Core210817T015901ZJulian
5348J210815T201547Zxash
02205AB1E210816T235830Zovs
026Jelly210816T231821ZNick Ken
137C clang210816T183500ZAZTECCO
091Ruby210816T073712ZG B
092JavaScript ES6210815T220255ZArnauld
058Haskell + hgl210815T214912ZWheat Wi
042Charcoal210815T214033ZNeil
116Python 3210815T200646Zhyperneu

Pip -xp, 32 bytes

^:iT(Yy+a@y%:#a)NiiPBya@i^@:i@?y

Takes the list (formatted like so: [1;2;-3]) as a command-line argument, and outputs a list of two lists. Attempt This Online! Or, verify all test cases.

Explanation

^:iT(Yy+a@y%:#a)NiiPBya@i^@:i@?y
                                  a is cmdline input, eval'd (-x flag);
                                  i is 0, y is "" (implicit)
^:i                               Split i and assign back to i: i is now [0]
   T                              Loop until
      y                            current index
       +a@y                        plus number at current index
           %:                      mod
             #a                    length of list
     Y                             (yank into y, making this the new index)
    (          )Ni                 is already in the list of indices traversed:
                  iPBy              Push the new index onto the list of indices
                                  After the loop, we have the list of unique
                                  indices traversed in i and the first repeated
                                  index in y
                      a@i         Values from a at each index in i
                         ^@:      split at
                            i@?y  the index of y in i

BQN, 39 bytesSBCS

↕∘≠⊸{⊏⟜𝕩¨2↑⊒⊸/⊸(+`⊑⊸=)⊸⊔0∾⊑˜⍟𝕨⟜⊑≠⊸|𝕨+𝕩}

Try it here.

↕∘≠⊸{⊏⟜𝕩¨2↑⊒⊸/⊸(+`⊑⊸=)⊸⊔0∾⊑˜⍟𝕨⟜⊑≠⊸|𝕨+𝕩} # 𝕩 is input, 𝕨 is indices 0,1,..,length-1
↕∘≠⊸{                                 } # pass indices into the main function as 𝕨
                                ≠⊸|𝕨+𝕩  # add indices to the input mod the length
                          ⊑˜⍟𝕨⟜⊑        # traverse from the first element a number
                                        #  of steps equal to the length,
                                        #  accumulating results
                        0∾              # prepend 0
           ⊒⊸/⊸(+`⊑⊸=)⊸⊔                # find the first value to repeat and
                                        #  partition by occurrences
         2↑                             # take the first 2 groups
     ⊏⟜𝕩¨                               # and use them to index into the input

jq, 146 bytes

length as$l|def x:((.[0]+.[1][-1])%$l+$l)%$l;def n:x as$x|.[1]|index($x);. as$i|[0,[],[]]|until(n;[$i[x],.[1]+[x],.[2]+[$i[x]]])|.[2][:n],.[2][n:]

Try it online!

C (gcc), 115 131 bytes

f(r,n,o,l,j)int*r,**o,*l;{int*t=malloc(4*n);for(*l=j=0;j+=o[0][(t[j]=++*l)-1]=r[j],!t[j=(j%n+n)%n];);*l-=l[1]=t[j]-1;o[1]=*o+l[1];}

Try it online!

Outputs [prefix, loop] into o and [len(loop), len(prefix)] into l. Expects these to have allocated enough memory to fit the output (though o[1] is discarded).

Husk, 32 29 25 23 bytes

Edit: -2 bytes thanks to Razetime

†!¹G-§eoUṠ-UUm←¡Sṙo!¹←ŀ

Try it online!

Outputs loop first, then first-visited.

Piece by piece:

Make an infinite list of lists of indices by repeatedly shifting by the input value indexed by the first element:

¡Sṙo!¹←ŀ

And get the first element of each of these: this is the list of indices:

m←

Now, get the longest non-repeating prefix (this includes one copy of the repeating elements):

U

And get the repeating indices:

oUṠ-U

Join these together into a list of 2 lists:

§e

And remove the first (the repeating indices) from the second (the prefix):

G-

Finally, use these to index into the original input:

†!¹

R, 121 118 108 102 101 99 bytes

-10 bytes and another -6 thanks to @Dominic van Essen

function(a,t=1){while(!(t=(t+a[t]-1)%%sum(a|1)+1)%in%T)T=c(T,t)
split(a[T],cut(cumsum(T==t),-1:1))}

Try it online!

The outputted lists have weird names (two intervals), but it I hope it's ok.

Jelly,  23  22 bytes

Quite possibly still beatable...

ĖUṙFḢƊƬḢ€⁺JœṖ€$§ṪọɗƇLṪ

A monadic Link that accepts the list and yields a list of lists.

Try it online!

How?

ĖUṙFḢƊƬḢ€⁺JœṖ€$§ṪọɗƇLṪ - Link: list of integers A=[a,b,...,x,y,...]
Ė                      - enumerate -> [[1,a],[2,b],...,[n,x],[m,y],...]
 U                     - upend     -> [[a,1],[b,2],...,[x,n],[y,m],...]
      Ƭ                - collect until a repeat under:
     Ɗ                 -   last three links as a monad, f(current=[[x,n],[y,m],...]):
   F                   -   flatten (current) -> [x,n,y,m,...]
  ṙ                    -   rotate (current) left by (each of [x,n,y,m,...])
    Ḣ                  -   head -> rotation by x
       Ḣ€              - head each -> leftmost of each, [[a,1],...,[x,n],...]
         ⁺             - repeat Ḣ€ -> visited elements in order, [a,...,x,...,last_of_loop]
              $        - last two links as a monad, f(V=[a,...,x,...,last_of_loop]):
          J            -   range of length -> [1,2,...,length(V)]
           œṖ€         -   partition (V) before each (of those) indices
                   Ƈ   - filter (all of these 2-partitions) keeping if:
                    L  -   use length (of A) on the right of...
                  ɗ    -   last three links as a dyad, f(partition, length(A)):
               §       -     sums
                Ṫ      -     tail -> length of the potential loop
                 ọ     -     how many times is that divisible by length(A)?
                             (positive (truthy) if an actual loop, else 0 (falsey))
                     Ṫ - tail

PowerShell Core, 156 145 bytes

for($v=@();!(($s=$v.IndexOf($i))+1);$i%=$l){$v+=,+$i
$t+=,($u=$args[+$i])
$i+=$u+($l=$args.Count)}if(--$l*$s){$t[$s..$l],$t[0..--$s]}else{$t,@()}

Try it online!

Takes a list as parameter.

Returns two lists: loop first then trajectory

Saved:

Not golfed:

$index = 0
$length = $args.Count
for ($indices = @(); ($truncateAt = $indices.IndexOf($index)) -eq -1) {
    $indices += , $index
    $trajectory += , $args[$index]
    $index = ($index + $args[$index] + $length) % $length
}
if (--$length -and $truncateAt) {
    ($trajectory[0..--$truncateAt] -join ','), ($trajectory[++$truncateAt..$length] -join ',')
}
else {
    '', ($trajectory -join ',')
}

J, 53 48 bytes

-5 thanks to Jonah!

(_2{.{~</.~]+./\@e.r)(]~.@,r=.(#@[|]+{~){:)^:_&0

Try it online!

Another approach would be to not build a list, but just repeat the index-shift-mod-loop <@# times, keeping the results, and then search for the loop. But I didn't get it shorter than this.

05AB1E, 22 bytes

0¸Δ¤DIsè+Ig%©ªÙ}D®QÅ¡è

Try it online!

Jelly, 26 bytes

L‘0ị+ị¥%L}ɗƬɗƬ%LḊḣ2fQ,ḟʋ/ị

Try it online!

A monadic link taking a list of integers and returning two lists of integers, with the looped integers first.

C (clang), 137 bytes

a,i,j;
#define f(l,z){int t[z]={i=j=0},h[z];for(;!(a=t[i]);i=(z+i+l[i]%z)%z)h[j]=l[i],t[i]=++j;for(i=0;i<j;)printf("! %d"+!!--a,h[i++]);}

Try it online!

l : list , z : length 
int t[z] : kinda sieve, every step sets the visited item to step number
h[z] : save the trajectory values in order for output
for(;!(a=t[i]) : we iterate until we find a visited item, saving in a the first already visited
;i=(z+i+l[i]%z)%z) : modulo hack 

at each iteration :
h[j]=l[i] : add item to output list
,t[i]=++j; : and update sieve

Output
for(i=0;i<j;) : j is the number of items visited
printf("! %d"+!!--a,h[i++]) 
a is the beginning of loop so we 
put a separator by including '!' in format string 

Ruby, 91 bytes

->l{*r=a=b=0;r<<a until b=r.index(a=(a+l[a])%l.size);[z=r[0,b],r-z].map{|x|l.values_at *x}}

Try it online!

JavaScript (ES6), 92 bytes

a=>[(g=p=>a=1/(i=g[p%=w=a.length])?[]:[q=a[p],...g(p+q+w*q*q,g[p]=k++)])(k=0).splice(0,i),a]

Try it online!

Commented

a => [                 // a[] = input array
  ( g = p =>           // g is a recursive function taking a position p
                       // the underlying object of g is also used to keep
                       // track of the positions that are visited
    a =                // update a[]
      1 / (            //
        i = g[         // reduce the position modulo the length w of the
          p %= w =     // array and load g[p] into i
            a.length   //
        ]              //
      ) ?              // if i is defined:
        []             //   we've found the loop: stop the recursion
      :                // else:
        [              //   update the output array:
          q = a[p],    //     load a[p] into q
          ...g(        //     do a recursive call:
            p + q +    //       add q to p
            w * q * q, //       also add w*q² to make sure it's >= 0
            g[p] = k++ //       save the index k into g[p] and increment k
          )            //     end of recursive call
        ]              //   end of array update
  )(k = 0)             // initial call to g with p = k = 0
  .splice(0, i),       // extract the non-looping part
  a                    // append the looping part
]                      //

Haskell + hgl, 61 60 58 bytes

(i:y)#x|i?>y=m(x!)&@sp(/=i)(rv y)|u<-(i+x!i)%l x:i:y=u#x
([0]#)

hgl is an experimental golfing library I am developing for Haskell. I started a few days ago and this is my first answer, and it's proof there is still a lot of room for improvement.

From this post I've learned that:

But here's how it actually works:

Vocab:

So this builds up a list of indices, when a index is added that is already in the list it stops and splits at the last occurrence of that index, and converts the indices to their values.

Charcoal, 42 bytes

≔⁰ζW¬№υζ«⊞υζ≔﹪⁺ζ§θζLθζ»≔⌕υζζUMυ§θιI⟦…υζ✂υζ

Try it online! Link is to verbose version of code. Explanation:

≔⁰ζ

Start at index 0.

W¬№υζ«

Repeat until a duplicate index is found.

⊞υζ

Save the current index.

≔﹪⁺ζ§θζLθζ

Calculate the new index.

»≔⌕υζζ

Find the position of the repeat.

UMυ§θι

Replace the indices with the values.

I⟦…υζ✂υζ

Output the values before and after the repeat as separate arrays.

Python 3, 116 bytes

f=lambda a,i=0,k=[]:i in k and[[a[q]for q in x]for x in[k[:k.index(i)],k[k.index(i):]]]or f(a,(i+a[i])%len(a),k+[i])

Try it online!