text:
Shell Glob Golfing
This task is to output the shortest path to a file, after glob expansion.
What is shell globbing? In most shells, you can use the * character in a path to represent any characters at the position. For example, If directory foo contains files bar baz and asdf, then foo/b* will expand to foo/bar foo/baz.
Now, lets say that the current directory contains a file called ihavealongname and nothing else. If I want to reference this file, I might type *, which will represent only that one file, rather than typing out the full name.
If the directory also contains a file called ialsohavealongname, I can't do *, as it will match both files. The I would have to do, at least, ih*.
The * pattern also works for matching directories above the file I'm looking for. If there are only two directories foo and bar, but foo contains only a file baz and bar contains file asdf, I can match foo/baz with */baz. Or, even more concisely, */b*. If bar was empty, */* would work.
Your task: Given a string array of paths that represent the "current directory" and a single target path, output the shortest possible string that would expand to only that target path after expanding *s.
The target path can be taken as it's own string, as an index into the array of paths, as the first item on the array of paths passed in, or some other convenient way that isn't hard-coding. Ask in comments if unsure.
The target path is guaranteed to be present in the "current directory".
You can assume that all paths contain only alphanumeric ASCII (and /s). You may take as input paths that are rooted (start with /) or relative (don't start with /).
If there are multiple equally short possibilities, return any or all of them.
This is code-golf, fewest bytes wins!
Test cases, thanks to Kevin Cruijssen.

Can I take a list of all files (in any order) as the input instead? Not all languages can do disk IO. Also, do we need to consider escape sequences?

So can we assume filenames don't contain spaces, newlines, backslashes, *, ?, [  etc ? It would maybe be easiest if you just state that file and directory names are alphanumeric

I suggest adding some test cases, as in: directory X contains (directories +) files /Y/A, /Y/B, /B, and then expected output for each individual file. Here is a pastebin as example. Also, can you confirm all the expected outputs are correct in this pastebin?

@KevinCruijssen In your first test1 directory I expect he wants */*/*z for test1/foo/baz and */*/a* for test1/foo/asdf. And i can imagine directory structures where the optmal selection happens partly in the directory globbing and partly in the file globbing making this challenge rather hard

@TonHospel Ah, you're indeed right. Updated pastebin. And I agree. Although it's a pretty cool challenge, the actual disk IO with front/back globbing makes it pretty difficult. And it's even possible to have both front AND back globbing if I'm not mistaken (i.e. /example and /exile: /example → /*a* OR /*m* OR /*p*; /exile → /*i*).

The actual disk I/O part will be boring in many languages. e.g. in perl I would just take the filename and replace all path components by * and run perl glob to get all filenames that can be relevant (e.g. foo/bar/baz becomes */*/*) . After that it becomes a string processing challenge. And that challenge is already hard enough. I think this challengwe would be cleaner as "given a list of alphanumeric (and /) relative paths, find the shortest glob that matches only this existing target path

@KevinCruijssen Sure, it's a fun challenge and should mostly keep the pure golfing languages away I think  you will need a real program (unless you generate all possible strings until you hit the shortest that works which is boring and will exponentially explode) Your current examples barely start to cover the cases you need to handle. Here's anther case: use a*f to select azzf from azzf, azzg, bzzf. Extend at will to a*b*c etc..

@tonhospel you can assume all filenames are alphanumeric ASCII.

@KevinCruijssen * matches 0 or more characers, not 1 or more. In your first test case, for example, *foo/* matches all the files. Thanks for making those though, I'll correct them now.

Possible duplicate of Shortest Unique Substring

@Xcali This is not a duplicate, and is, in fact, significantly more challenging due to the need to consider globs across multiple directories and due to the fact that a string can be identified by multiple of its substrings together.

@Pavel Thanks for correcting them and adding them to the challenge description. I just spotted two small mistakes (I made one of them myself in my paste-bin as well): foo/bar/test Expected: */bar/* OR */*/*ar/* (the one after the OR contains one leading */ too many). And foo/barber/testing Expected: */*/*ting can be */*/*ti* which is 1 byte shorter. +1 from me.

@TonHospel I'm convinced. You now take an array of paths as input.

@KevinCruijssen Thanks, updated.

@WeijunZhou I've changed my mind about input. You can now take an array of paths.

Correction again: foo/barber/testing Expected: */*/*ti* can be */*/t*g. Just finished my code (will golf it some more and post it in a moment), and noticed this one was incorrect.

@KevinCruijssen done

I'm confused by the new input format.  What is an array of paths?  Could we get a more detailed explanation of the input, maybe with an example?

@WheatWizard it's list of strings. The strings represent paths.

Perl 5, 136 107 102 bytes
Includes +2 for n0
Give list of files on STDIN. The first one is assumed to be the target file
perl -n0E '@a="";for$a(@a){s%%s/(?=$a
)/;/g;$$_//=push@a,map$_.$a,/./g,"\\w*";/^;/>/
;/&&1/!say$a=~s/\\w//gr%e}'
foo/barber/test
foo/barber/testing
foo/barber/coding
foo/test
foo/bar/test
^D

Just the code without making the newlines literal:
@a="";for$a(@a){s%%s/(?=$a\n)/;/g;$$_//=push@a,map$_.$a,/./g,"\\w*";/^;/>/\n;/&&1/!say$a=~s/\\w//gr%e}

Crashes intentionally after printing the solution.
Still seems too long (the use of $a and 1/0 are very awkward), but it's a start and should be reasonably efficient.
Try it online!
How it works
The program builds candidate globs by growing them from the back to the front starting with the empty string. It does this in a breadth first way, so first globs of length 0 are tried (only ``), then length 1 (like t, i, *), next length 2 (like fb, i*, *g, **), next length 3 and so on until a glob is found that only matches the first path. This will then be the shortest glob that solves the problem (others of the same length may exist).
The globs of length n+1 are generated from the globs of length n by prepending each character from the list of paths and also * in front of each glob of length n. So e.g. length 3 glob *i* will contribute length 4 globs f*i*, o*i*, o*i*, /*i*, b*i* ... s*i*, t*i* and finally **i*. Notice that every character from the list of input paths is prepended even if it appears multiple times or makes no sense whatsoever because it leads to something that can never match.
Doing this naively would lead to a combinatorial explosion. That is why every candidate glob gets evaluated for how useful it is by determining at which points in the paths it could match if the glob was used at the end of a complete glob. I do this by inserting a ; at each place where a match is possible. For example for the glob t* I will get the string:
foo/barber/;tes;t
foo/barber/;tes;ting
foo/barber/coding
foo/;tes;t
foo/bar/;tes;t

This represents the "distinguishing power" of the glob. Every glob that has exactly the same distinguishing power is equally good. If you replace them by each other at the end of a complete glob they will all match exactly the same paths. So you can just as well use the shortest one.
So when considering the length n globs I first look at its distinguishing power. If it has been seen before there was another glob of length n or shorter that was already considered and expanded, so this glob is pointless and gets pruned. This will for example get rid of candidates like **i* since the same distinguishing power will already have been seen as *i*. It also prunes impossible candidates like f*i* since the distinguishing string will have no ; and just be the original list of paths. Only the very first impossible glob will be accepted, all the others will be seen as having the same distinguishing power and will be pruned. And even that first one won't really get expanded since all expansions are still impossible and will be pruned when they are considered. Simularly in* will be pruned by i* etc.
The above leads to very aggressive pruning and the program is therefore able to handle complex cases in a very short time. A major inefficiency though is that it prefixes the candidate globs with all possible characters, not only the ones just before a ; in target path part of the distinguishing string. All added characters that are not in front of a ; are no problem since they lead to an impossible glob which will be pruned when it gets considered, but that still leaves the characters just before ; in the other paths. So in the end the program also builds globs that will be able match any combination of the given paths. It has no idea that it should be concentrating on the first path.
Now consider a solution to the problem. In the given example that could be */*er/t. This gives the following distinguishing string:
;f;o;o;/barber/test
foo/barber/testing
foo/barber/coding
foo/test
foo/bar/test

I recognize a solution by having a ; at the first position (so it matches the first path) and not having a ; at the start of any other path (so the others don't match)
With the algorithm explained I now get to the actual program:
The candidate globs will be in array @a which I loop over using variable $a which contains the glob currently under consideration. Instead of * in the glob I will however use \w* so $a is actually a regex instead of a glob. I'm going to abuse a weirdness of the perl for loop that you can append elements to the array being looped while the loop is running and these new elements will get picked up in the loop. Since when generating the length n+1 globs all length n globs are already on array @a this is breadth first.
Due to the -n0 option (implicit loop over the whole input) the list of paths is in $_ as one big string with each path terminated with a newline
@a="";                    Start everything with the length 0 glob
for$a(@a){    }           Loop over candidates in a breadth first way

Inside the { } we have:
s/(?=$a\n)/;/g            Loop over the paths and insert a ; at every
                          position that the suffix glob can match by
                          looking ahead and checking that the regex
                          under consideration can match up to the end of
                          the path we are in. The distinguishing sting is
                          now in `$_`.

Oops, I just destroyed $_ and I will need it for the next loop. So wrap the
actual working code inside
s%%  ...code.. %e

This matches the empty string at the start of $_ and allows you to run code to determine what it gets replaced with. If I make sure that that code evaluates to the empty string $_ will at the end remain unchanged even if I change $_ during code.
Going back to just after I replaced $_ by the distinguishing string:
$$_//= expression

This is like:
$seen{$_} //= expression

// in perl is'defined or. It's like a short circuiting or where the second argument is only evaluated if the first one is undef. And it can be combined with an assignment just like += in some other languages. So if they key $_ in hash %seen is undef (which is is what you get when accessing a non-existing element) only then execute expression and assign it as value to key $_. So if I make sure expression does not return undef that basically means "evaluate expression if and only if this is the first time we see that particular distinguishing string". And because $_ is guaranteed to contain a \n it is in fact safe to abuse the perl global hash to store the distinguishing strings, so $$_ instead of $seen{$_}
For the expression I use:
push@a,map$_.$a,/./g,"\\w*"

Basically "For every character (except newline) in the distinguishing string and also * prepend it to the current glob and push that on the array of candidate globs". Execpt I use \w* for * to get a valid regex (I could use '' instead of "" to get rid of one backslash but then I couldn't run my code from the command line). Notice that this also picks up the ; and adds them to the candidate globs but when later testing them to the restored $_ which has no ; that will again be an impossible glob and get pruned.
/^;/>/\n;/ &&      If the distinguishing string corresponds to a solution

say$a=~s/\\w//gr   Then replace all \w* back to * and print the solution

1/!                Say returns 1 so this becomes a division by 0.
                   The program exits by crashing after solving it

Notice that /^;/>/\n;/ has a value equivalent to the empty string in case a solution was not yet found, so this will function as empty replacement string and $_ gets restored

I get an error on TIO but it works locally. Do you know why that is?

@Pavel The -E activates the latest language level. You need at least perl 5.10.0 to be able to use say. So put use 5.10.0; in the header section and it will work. Options to set the language level count as free anyways even if you couldn't also do it using -E. In fact all options count as free nowadays (so I don't even have to count n0) but I consider that too lenient for perl

Exiting with an error is fine, so your 1/ solution is valid! I need to remember that too...

Java 10, 854 824 796 738 728 703 688 655 652 647 624 bytes
import java.util.*;a->f->{var L=new Stack();List<String>s;int i=999,j,k;for(var t:f.split("/")){s=new java.util.concurrent.CopyOnWriteArrayList();s.add(t);for(k=1;k>0;){k=0;for(var x:s)for(j=0;j<x.length();)if(!s.contains(f=x.substring(0,j)+"~"+x.substring(++j))){s.add(f);k=1;}}for(var x:s)s.add(x.replaceAll("~+","\\*"));L.add(s);}p(L,s=new Stack(),0,f="");for(var y:s){k=0;for(var x:a)if(x.matches(y.replace("*",".*"))&x.split("/").length==y.split("/").length)k++;if(k==1&(j=y.length())<i){f=y;i=j;}}return f;};void p(List L,List r,int d,String c){if(d==L.size())r.add(c);else for(var o:(List)L.get(d))p(L,r,d+1,c+"/"+o);}

What a mess.. This is certainly not an easy challenge in Java. Can definitely be golfed by a couple hundred bytes, but I'm just glad it's finally working now. Told ya. :)
-5 bytes thanks to @ceilingcat.
-23 bytes switching from Java 8 to Java 10
Input as a String-array of file-paths (with directories as separated items, and all items containing a leading /), and a String with input file-path to grop.
Explanation:
Try it online. (The test cases with ialsohavealongname/ihavealongnameaswell are slightly reduced in length and s.add(x.replaceAll("~+","\\*")); has been replaced with {s.remove(x);s.add(x.replaceAll("~+","\\*"));} to work in 5-10 seconds on TIO, instead of timing out after 60+ sec.)
import java.util.*;   // Required import for List and Stack

// Method with String-array and String parameters and String return-type
a->f->{
  var L=new Stack();  //  Create a List of Lists
  List<String>s;      //  List of Strings (uninitialized)
  int i=999,j,k;      //  Three integers (`i` starting at 999,
                      //   because 260 is the maximum file-path length in Windows)
  for(var t:f.split("/")){
                      //  Loop over the input file-path split by "/":
    s=new java.util.concurrent.CopyOnWriteArrayList();
                      //  Create a List (which we can modify while iterating it)
    s.add(t);         //  Add the input to this List
    for(k=1;k>0;){    //  Loop as long as there are new items added to the List
      k=0;            //   Reset the newAdded-flag to false
      for(var x:s)    //   And inner loop over the List
        for(j=0;j<t.length();)
                      //    Inner loop `j` in range [0,length-of-item):
          if(!s.contains(f=x.substring(0,j)+"~"+x.substring(++j))){
                      //     Replace the character at index `j` with a '~'
                      //     And if it's a new item:
            s.add(f); //      Add it to the List
            k=1;}}    //      And set the newAdded-flag to true
    for(var x:s)      //  Loop over the List again
      s.add(x.replaceAll("~+","\\*")));
                      //   And replace all 1 or more '~' with a single asterisk
                      //   (NOTE: To reduce bytes it doesn't remove the existing items)
    L.add(s);}        //   Add this List to the List of Lists
  p(L,s=new Stack(),0,"");
                      //  Generate all permutations of the groppings
                      //  (List `s` now contains all groppings of the given file-path)
  for(var y:s){       //  Loop over the groppings in the String-List:
    k=0;              //   Reset integer `k` to 0
    for(var x:a)      //   Inner loop over the input file-paths:
      if(x.matches(y.replace("*",".*"))
                      //    If the current file-path matches the current gropping
         x.split("/").length==y.split("/").length)
                      //    and the amount of slashes are the same:
         k++;         //     Increase integer `k` by 1
    if(k==1           //   If only one of the file-paths matched,
       &(j=y.length())<i){
                      //   and the length is shorter than `i`:
      f=y;            //    Replace the result with this gropping file-path
      i=j;}}          //    And also replace `i` with this shorter `j`
  return f;}          //  Finally return this shortest gropping file-path

// Separated method to generate gropping file-path permutations given a List of Lists
void p(List L,List r,int d,String c){
  if(d==L.size())     //  If we've reached the final depth
    r.add(c);         //   Add the current gropping-file path to the result-List
  else                //  Else:
    for(var o:(List)L.get(d))
                      //   Loop over the List of the current depth:
      p(L,r,d+1,      //    Recursive call with depth+1,
        c+"/"+o);}    //    and current + "/" + item of loop

Additional general explanation:
Example: Let's take /foo, /foo/bar, /foo/barber, /foo/bar/test, /foo/barber/test, /foo/barber/testing, /foo/barber/coding, /foo/test as given file-paths, and foo/bar/test as input file-path to grop.
1) I start by splitting the file-path input by /, and generate all file-groppings of these separated words:
foo: [foo, *oo, f*o, fo*, *o, *o*, f*, *]
bar: [bar, *ar, b*r, ba*, *r, *a*, b*, *]
test: [test, *est, t*st, te*t, tes*, *st, *e*t, *es*, t*t, t*s*, te*, *t, *s*, *e*, t*, *]

2) I then generate all permutations with these words in the same order (reapplying the / in between and at the front):
[/foo/bar/test, /foo/bar/*est, /foo/bar/t*st, /foo/bar/te*t, /foo/bar/tes*, /foo/bar/*st, /foo/bar/*e*t, /foo/bar/*es*, /foo/bar/t*t, /foo/bar/t*s*, /foo/bar/te*, /foo/bar/*t, /foo/bar/*s*, /foo/bar/*e*, /foo/bar/t*, /foo/bar/*, /foo/*ar/test, /foo/*ar/*est, /foo/*ar/t*st, /foo/*ar/te*t, /foo/*ar/tes*, /foo/*ar/*st, /foo/*ar/*e*t, /foo/*ar/*es*, /foo/*ar/t*t, /foo/*ar/t*s*, /foo/*ar/te*, /foo/*ar/*t, /foo/*ar/*s*, /foo/*ar/*e*, /foo/*ar/t*, /foo/*ar/*, /foo/b*r/test, /foo/b*r/*est, /foo/b*r/t*st, /foo/b*r/te*t, /foo/b*r/tes*, /foo/b*r/*st, /foo/b*r/*e*t, /foo/b*r/*es*, /foo/b*r/t*t, /foo/b*r/t*s*, /foo/b*r/te*, /foo/b*r/*t, /foo/b*r/*s*, /foo/b*r/*e*, /foo/b*r/t*, /foo/b*r/*, /foo/ba*/test, /foo/ba*/*est, /foo/ba*/t*st, /foo/ba*/te*t, /foo/ba*/tes*, /foo/ba*/*st, /foo/ba*/*e*t, /foo/ba*/*es*, /foo/ba*/t*t, /foo/ba*/t*s*, /foo/ba*/te*, /foo/ba*/*t, /foo/ba*/*s*, /foo/ba*/*e*, /foo/ba*/t*, /foo/ba*/*, /foo/*r/test, /foo/*r/*est, /foo/*r/t*st, /foo/*r/te*t, /foo/*r/tes*, /foo/*r/*st, /foo/*r/*e*t, /foo/*r/*es*, /foo/*r/t*t, /foo/*r/t*s*, /foo/*r/te*, /foo/*r/*t, /foo/*r/*s*, /foo/*r/*e*, /foo/*r/t*, /foo/*r/*, /foo/*a*/test, /foo/*a*/*est, /foo/*a*/t*st, /foo/*a*/te*t, /foo/*a*/tes*, /foo/*a*/*st, /foo/*a*/*e*t, /foo/*a*/*es*, /foo/*a*/t*t, /foo/*a*/t*s*, /foo/*a*/te*, /foo/*a*/*t, /foo/*a*/*s*, /foo/*a*/*e*, /foo/*a*/t*, /foo/*a*/*, /foo/b*/test, /foo/b*/*est, /foo/b*/t*st, /foo/b*/te*t, /foo/b*/tes*, /foo/b*/*st, /foo/b*/*e*t, /foo/b*/*es*, /foo/b*/t*t, /foo/b*/t*s*, /foo/b*/te*, /foo/b*/*t, /foo/b*/*s*, /foo/b*/*e*, /foo/b*/t*, /foo/b*/*, /foo/*/test, /foo/*/*est, /foo/*/t*st, /foo/*/te*t, /foo/*/tes*, /foo/*/*st, /foo/*/*e*t, /foo/*/*es*, /foo/*/t*t, /foo/*/t*s*, /foo/*/te*, /foo/*/*t, /foo/*/*s*, /foo/*/*e*, /foo/*/t*, /foo/*/*, /*oo/bar/test, /*oo/bar/*est, /*oo/bar/t*st, /*oo/bar/te*t, /*oo/bar/tes*, /*oo/bar/*st, /*oo/bar/*e*t, /*oo/bar/*es*, /*oo/bar/t*t, /*oo/bar/t*s*, /*oo/bar/te*, /*oo/bar/*t, /*oo/bar/*s*, /*oo/bar/*e*, /*oo/bar/t*, /*oo/bar/*, /*oo/*ar/test, /*oo/*ar/*est, /*oo/*ar/t*st, /*oo/*ar/te*t, /*oo/*ar/tes*, /*oo/*ar/*st, /*oo/*ar/*e*t, /*oo/*ar/*es*, /*oo/*ar/t*t, /*oo/*ar/t*s*, /*oo/*ar/te*, /*oo/*ar/*t, /*oo/*ar/*s*, /*oo/*ar/*e*, /*oo/*ar/t*, /*oo/*ar/*, /*oo/b*r/test, /*oo/b*r/*est, /*oo/b*r/t*st, /*oo/b*r/te*t, /*oo/b*r/tes*, /*oo/b*r/*st, /*oo/b*r/*e*t, /*oo/b*r/*es*, /*oo/b*r/t*t, /*oo/b*r/t*s*, /*oo/b*r/te*, /*oo/b*r/*t, /*oo/b*r/*s*, /*oo/b*r/*e*, /*oo/b*r/t*, /*oo/b*r/*, /*oo/ba*/test, /*oo/ba*/*est, /*oo/ba*/t*st, /*oo/ba*/te*t, /*oo/ba*/tes*, /*oo/ba*/*st, /*oo/ba*/*e*t, /*oo/ba*/*es*, /*oo/ba*/t*t, /*oo/ba*/t*s*, /*oo/ba*/te*, /*oo/ba*/*t, /*oo/ba*/*s*, /*oo/ba*/*e*, /*oo/ba*/t*, /*oo/ba*/*, /*oo/*r/test, /*oo/*r/*est, /*oo/*r/t*st, /*oo/*r/te*t, /*oo/*r/tes*, /*oo/*r/*st, /*oo/*r/*e*t, /*oo/*r/*es*, /*oo/*r/t*t, /*oo/*r/t*s*, /*oo/*r/te*, /*oo/*r/*t, /*oo/*r/*s*, /*oo/*r/*e*, /*oo/*r/t*, /*oo/*r/*, /*oo/*a*/test, /*oo/*a*/*est, /*oo/*a*/t*st, /*oo/*a*/te*t, /*oo/*a*/tes*, /*oo/*a*/*st, /*oo/*a*/*e*t, /*oo/*a*/*es*, /*oo/*a*/t*t, /*oo/*a*/t*s*, /*oo/*a*/te*, /*oo/*a*/*t, /*oo/*a*/*s*, /*oo/*a*/*e*, /*oo/*a*/t*, /*oo/*a*/*, /*oo/b*/test, /*oo/b*/*est, /*oo/b*/t*st, /*oo/b*/te*t, /*oo/b*/tes*, /*oo/b*/*st, /*oo/b*/*e*t, /*oo/b*/*es*, /*oo/b*/t*t, /*oo/b*/t*s*, /*oo/b*/te*, /*oo/b*/*t, /*oo/b*/*s*, /*oo/b*/*e*, /*oo/b*/t*, /*oo/b*/*, /*oo/*/test, /*oo/*/*est, /*oo/*/t*st, /*oo/*/te*t, /*oo/*/tes*, /*oo/*/*st, /*oo/*/*e*t, /*oo/*/*es*, /*oo/*/t*t, /*oo/*/t*s*, /*oo/*/te*, /*oo/*/*t, /*oo/*/*s*, /*oo/*/*e*, /*oo/*/t*, /*oo/*/*, /f*o/bar/test, /f*o/bar/*est, /f*o/bar/t*st, /f*o/bar/te*t, /f*o/bar/tes*, /f*o/bar/*st, /f*o/bar/*e*t, /f*o/bar/*es*, /f*o/bar/t*t, /f*o/bar/t*s*, /f*o/bar/te*, /f*o/bar/*t, /f*o/bar/*s*, /f*o/bar/*e*, /f*o/bar/t*, /f*o/bar/*, /f*o/*ar/test, /f*o/*ar/*est, /f*o/*ar/t*st, /f*o/*ar/te*t, /f*o/*ar/tes*, /f*o/*ar/*st, /f*o/*ar/*e*t, /f*o/*ar/*es*, /f*o/*ar/t*t, /f*o/*ar/t*s*, /f*o/*ar/te*, /f*o/*ar/*t, /f*o/*ar/*s*, /f*o/*ar/*e*, /f*o/*ar/t*, /f*o/*ar/*, /f*o/b*r/test, /f*o/b*r/*est, /f*o/b*r/t*st, /f*o/b*r/te*t, /f*o/b*r/tes*, /f*o/b*r/*st, /f*o/b*r/*e*t, /f*o/b*r/*es*, /f*o/b*r/t*t, /f*o/b*r/t*s*, /f*o/b*r/te*, /f*o/b*r/*t, /f*o/b*r/*s*, /f*o/b*r/*e*, /f*o/b*r/t*, /f*o/b*r/*, /f*o/ba*/test, /f*o/ba*/*est, /f*o/ba*/t*st, /f*o/ba*/te*t, /f*o/ba*/tes*, /f*o/ba*/*st, /f*o/ba*/*e*t, /f*o/ba*/*es*, /f*o/ba*/t*t, /f*o/ba*/t*s*, /f*o/ba*/te*, /f*o/ba*/*t, /f*o/ba*/*s*, /f*o/ba*/*e*, /f*o/ba*/t*, /f*o/ba*/*, /f*o/*r/test, /f*o/*r/*est, /f*o/*r/t*st, /f*o/*r/te*t, /f*o/*r/tes*, /f*o/*r/*st, /f*o/*r/*e*t, /f*o/*r/*es*, /f*o/*r/t*t, /f*o/*r/t*s*, /f*o/*r/te*, /f*o/*r/*t, /f*o/*r/*s*, /f*o/*r/*e*, /f*o/*r/t*, /f*o/*r/*, /f*o/*a*/test, /f*o/*a*/*est, /f*o/*a*/t*st, /f*o/*a*/te*t, /f*o/*a*/tes*, /f*o/*a*/*st, /f*o/*a*/*e*t, /f*o/*a*/*es*, /f*o/*a*/t*t, /f*o/*a*/t*s*, /f*o/*a*/te*, /f*o/*a*/*t, /f*o/*a*/*s*, /f*o/*a*/*e*, /f*o/*a*/t*, /f*o/*a*/*, /f*o/b*/test, /f*o/b*/*est, /f*o/b*/t*st, /f*o/b*/te*t, /f*o/b*/tes*, /f*o/b*/*st, /f*o/b*/*e*t, /f*o/b*/*es*, /f*o/b*/t*t, /f*o/b*/t*s*, /f*o/b*/te*, /f*o/b*/*t, /f*o/b*/*s*, /f*o/b*/*e*, /f*o/b*/t*, /f*o/b*/*, /f*o/*/test, /f*o/*/*est, /f*o/*/t*st, /f*o/*/te*t, /f*o/*/tes*, /f*o/*/*st, /f*o/*/*e*t, /f*o/*/*es*, /f*o/*/t*t, /f*o/*/t*s*, /f*o/*/te*, /f*o/*/*t, /f*o/*/*s*, /f*o/*/*e*, /f*o/*/t*, /f*o/*/*, /fo*/bar/test, /fo*/bar/*est, /fo*/bar/t*st, /fo*/bar/te*t, /fo*/bar/tes*, /fo*/bar/*st, /fo*/bar/*e*t, /fo*/bar/*es*, /fo*/bar/t*t, /fo*/bar/t*s*, /fo*/bar/te*, /fo*/bar/*t, /fo*/bar/*s*, /fo*/bar/*e*, /fo*/bar/t*, /fo*/bar/*, /fo*/*ar/test, /fo*/*ar/*est, /fo*/*ar/t*st, /fo*/*ar/te*t, /fo*/*ar/tes*, /fo*/*ar/*st, /fo*/*ar/*e*t, /fo*/*ar/*es*, /fo*/*ar/t*t, /fo*/*ar/t*s*, /fo*/*ar/te*, /fo*/*ar/*t, /fo*/*ar/*s*, /fo*/*ar/*e*, /fo*/*ar/t*, /fo*/*ar/*, /fo*/b*r/test, /fo*/b*r/*est, /fo*/b*r/t*st, /fo*/b*r/te*t, /fo*/b*r/tes*, /fo*/b*r/*st, /fo*/b*r/*e*t, /fo*/b*r/*es*, /fo*/b*r/t*t, /fo*/b*r/t*s*, /fo*/b*r/te*, /fo*/b*r/*t, /fo*/b*r/*s*, /fo*/b*r/*e*, /fo*/b*r/t*, /fo*/b*r/*, /fo*/ba*/test, /fo*/ba*/*est, /fo*/ba*/t*st, /fo*/ba*/te*t, /fo*/ba*/tes*, /fo*/ba*/*st, /fo*/ba*/*e*t, /fo*/ba*/*es*, /fo*/ba*/t*t, /fo*/ba*/t*s*, /fo*/ba*/te*, /fo*/ba*/*t, /fo*/ba*/*s*, /fo*/ba*/*e*, /fo*/ba*/t*, /fo*/ba*/*, /fo*/*r/test, /fo*/*r/*est, /fo*/*r/t*st, /fo*/*r/te*t, /fo*/*r/tes*, /fo*/*r/*st, /fo*/*r/*e*t, /fo*/*r/*es*, /fo*/*r/t*t, /fo*/*r/t*s*, /fo*/*r/te*, /fo*/*r/*t, /fo*/*r/*s*, /fo*/*r/*e*, /fo*/*r/t*, /fo*/*r/*, /fo*/*a*/test, /fo*/*a*/*est, /fo*/*a*/t*st, /fo*/*a*/te*t, /fo*/*a*/tes*, /fo*/*a*/*st, /fo*/*a*/*e*t, /fo*/*a*/*es*, /fo*/*a*/t*t, /fo*/*a*/t*s*, /fo*/*a*/te*, /fo*/*a*/*t, /fo*/*a*/*s*, /fo*/*a*/*e*, /fo*/*a*/t*, /fo*/*a*/*, /fo*/b*/test, /fo*/b*/*est, /fo*/b*/t*st, /fo*/b*/te*t, /fo*/b*/tes*, /fo*/b*/*st, /fo*/b*/*e*t, /fo*/b*/*es*, /fo*/b*/t*t, /fo*/b*/t*s*, /fo*/b*/te*, /fo*/b*/*t, /fo*/b*/*s*, /fo*/b*/*e*, /fo*/b*/t*, /fo*/b*/*, /fo*/*/test, /fo*/*/*est, /fo*/*/t*st, /fo*/*/te*t, /fo*/*/tes*, /fo*/*/*st, /fo*/*/*e*t, /fo*/*/*es*, /fo*/*/t*t, /fo*/*/t*s*, /fo*/*/te*, /fo*/*/*t, /fo*/*/*s*, /fo*/*/*e*, /fo*/*/t*, /fo*/*/*, /*o/bar/test, /*o/bar/*est, /*o/bar/t*st, /*o/bar/te*t, /*o/bar/tes*, /*o/bar/*st, /*o/bar/*e*t, /*o/bar/*es*, /*o/bar/t*t, /*o/bar/t*s*, /*o/bar/te*, /*o/bar/*t, /*o/bar/*s*, /*o/bar/*e*, /*o/bar/t*, /*o/bar/*, /*o/*ar/test, /*o/*ar/*est, /*o/*ar/t*st, /*o/*ar/te*t, /*o/*ar/tes*, /*o/*ar/*st, /*o/*ar/*e*t, /*o/*ar/*es*, /*o/*ar/t*t, /*o/*ar/t*s*, /*o/*ar/te*, /*o/*ar/*t, /*o/*ar/*s*, /*o/*ar/*e*, /*o/*ar/t*, /*o/*ar/*, /*o/b*r/test, /*o/b*r/*est, /*o/b*r/t*st, /*o/b*r/te*t, /*o/b*r/tes*, /*o/b*r/*st, /*o/b*r/*e*t, /*o/b*r/*es*, /*o/b*r/t*t, /*o/b*r/t*s*, /*o/b*r/te*, /*o/b*r/*t, /*o/b*r/*s*, /*o/b*r/*e*, /*o/b*r/t*, /*o/b*r/*, /*o/ba*/test, /*o/ba*/*est, /*o/ba*/t*st, /*o/ba*/te*t, /*o/ba*/tes*, /*o/ba*/*st, /*o/ba*/*e*t, /*o/ba*/*es*, /*o/ba*/t*t, /*o/ba*/t*s*, /*o/ba*/te*, /*o/ba*/*t, /*o/ba*/*s*, /*o/ba*/*e*, /*o/ba*/t*, /*o/ba*/*, /*o/*r/test, /*o/*r/*est, /*o/*r/t*st, /*o/*r/te*t, /*o/*r/tes*, /*o/*r/*st, /*o/*r/*e*t, /*o/*r/*es*, /*o/*r/t*t, /*o/*r/t*s*, /*o/*r/te*, /*o/*r/*t, /*o/*r/*s*, /*o/*r/*e*, /*o/*r/t*, /*o/*r/*, /*o/*a*/test, /*o/*a*/*est, /*o/*a*/t*st, /*o/*a*/te*t, /*o/*a*/tes*, /*o/*a*/*st, /*o/*a*/*e*t, /*o/*a*/*es*, /*o/*a*/t*t, /*o/*a*/t*s*, /*o/*a*/te*, /*o/*a*/*t, /*o/*a*/*s*, /*o/*a*/*e*, /*o/*a*/t*, /*o/*a*/*, /*o/b*/test, /*o/b*/*est, /*o/b*/t*st, /*o/b*/te*t, /*o/b*/tes*, /*o/b*/*st, /*o/b*/*e*t, /*o/b*/*es*, /*o/b*/t*t, /*o/b*/t*s*, /*o/b*/te*, /*o/b*/*t, /*o/b*/*s*, /*o/b*/*e*, /*o/b*/t*, /*o/b*/*, /*o/*/test, /*o/*/*est, /*o/*/t*st, /*o/*/te*t, /*o/*/tes*, /*o/*/*st, /*o/*/*e*t, /*o/*/*es*, /*o/*/t*t, /*o/*/t*s*, /*o/*/te*, /*o/*/*t, /*o/*/*s*, /*o/*/*e*, /*o/*/t*, /*o/*/*, /*o*/bar/test, /*o*/bar/*est, /*o*/bar/t*st, /*o*/bar/te*t, /*o*/bar/tes*, /*o*/bar/*st, /*o*/bar/*e*t, /*o*/bar/*es*, /*o*/bar/t*t, /*o*/bar/t*s*, /*o*/bar/te*, /*o*/bar/*t, /*o*/bar/*s*, /*o*/bar/*e*, /*o*/bar/t*, /*o*/bar/*, /*o*/*ar/test, /*o*/*ar/*est, /*o*/*ar/t*st, /*o*/*ar/te*t, /*o*/*ar/tes*, /*o*/*ar/*st, /*o*/*ar/*e*t, /*o*/*ar/*es*, /*o*/*ar/t*t, /*o*/*ar/t*s*, /*o*/*ar/te*, /*o*/*ar/*t, /*o*/*ar/*s*, /*o*/*ar/*e*, /*o*/*ar/t*, /*o*/*ar/*, /*o*/b*r/test, /*o*/b*r/*est, /*o*/b*r/t*st, /*o*/b*r/te*t, /*o*/b*r/tes*, /*o*/b*r/*st, /*o*/b*r/*e*t, /*o*/b*r/*es*, /*o*/b*r/t*t, /*o*/b*r/t*s*, /*o*/b*r/te*, /*o*/b*r/*t, /*o*/b*r/*s*, /*o*/b*r/*e*, /*o*/b*r/t*, /*o*/b*r/*, /*o*/ba*/test, /*o*/ba*/*est, /*o*/ba*/t*st, /*o*/ba*/te*t, /*o*/ba*/tes*, /*o*/ba*/*st, /*o*/ba*/*e*t, /*o*/ba*/*es*, /*o*/ba*/t*t, /*o*/ba*/t*s*, /*o*/ba*/te*, /*o*/ba*/*t, /*o*/ba*/*s*, /*o*/ba*/*e*, /*o*/ba*/t*, /*o*/ba*/*, /*o*/*r/test, /*o*/*r/*est, /*o*/*r/t*st, /*o*/*r/te*t, /*o*/*r/tes*, /*o*/*r/*st, /*o*/*r/*e*t, /*o*/*r/*es*, /*o*/*r/t*t, /*o*/*r/t*s*, /*o*/*r/te*, /*o*/*r/*t, /*o*/*r/*s*, /*o*/*r/*e*, /*o*/*r/t*, /*o*/*r/*, /*o*/*a*/test, /*o*/*a*/*est, /*o*/*a*/t*st, /*o*/*a*/te*t, /*o*/*a*/tes*, /*o*/*a*/*st, /*o*/*a*/*e*t, /*o*/*a*/*es*, /*o*/*a*/t*t, /*o*/*a*/t*s*, /*o*/*a*/te*, /*o*/*a*/*t, /*o*/*a*/*s*, /*o*/*a*/*e*, /*o*/*a*/t*, /*o*/*a*/*, /*o*/b*/test, /*o*/b*/*est, /*o*/b*/t*st, /*o*/b*/te*t, /*o*/b*/tes*, /*o*/b*/*st, /*o*/b*/*e*t, /*o*/b*/*es*, /*o*/b*/t*t, /*o*/b*/t*s*, /*o*/b*/te*, /*o*/b*/*t, /*o*/b*/*s*, /*o*/b*/*e*, /*o*/b*/t*, /*o*/b*/*, /*o*/*/test, /*o*/*/*est, /*o*/*/t*st, /*o*/*/te*t, /*o*/*/tes*, /*o*/*/*st, /*o*/*/*e*t, /*o*/*/*es*, /*o*/*/t*t, /*o*/*/t*s*, /*o*/*/te*, /*o*/*/*t, /*o*/*/*s*, /*o*/*/*e*, /*o*/*/t*, /*o*/*/*, /f*/bar/test, /f*/bar/*est, /f*/bar/t*st, /f*/bar/te*t, /f*/bar/tes*, /f*/bar/*st, /f*/bar/*e*t, /f*/bar/*es*, /f*/bar/t*t, /f*/bar/t*s*, /f*/bar/te*, /f*/bar/*t, /f*/bar/*s*, /f*/bar/*e*, /f*/bar/t*, /f*/bar/*, /f*/*ar/test, /f*/*ar/*est, /f*/*ar/t*st, /f*/*ar/te*t, /f*/*ar/tes*, /f*/*ar/*st, /f*/*ar/*e*t, /f*/*ar/*es*, /f*/*ar/t*t, /f*/*ar/t*s*, /f*/*ar/te*, /f*/*ar/*t, /f*/*ar/*s*, /f*/*ar/*e*, /f*/*ar/t*, /f*/*ar/*, /f*/b*r/test, /f*/b*r/*est, /f*/b*r/t*st, /f*/b*r/te*t, /f*/b*r/tes*, /f*/b*r/*st, /f*/b*r/*e*t, /f*/b*r/*es*, /f*/b*r/t*t, /f*/b*r/t*s*, /f*/b*r/te*, /f*/b*r/*t, /f*/b*r/*s*, /f*/b*r/*e*, /f*/b*r/t*, /f*/b*r/*, /f*/ba*/test, /f*/ba*/*est, /f*/ba*/t*st, /f*/ba*/te*t, /f*/ba*/tes*, /f*/ba*/*st, /f*/ba*/*e*t, /f*/ba*/*es*, /f*/ba*/t*t, /f*/ba*/t*s*, /f*/ba*/te*, /f*/ba*/*t, /f*/ba*/*s*, /f*/ba*/*e*, /f*/ba*/t*, /f*/ba*/*, /f*/*r/test, /f*/*r/*est, /f*/*r/t*st, /f*/*r/te*t, /f*/*r/tes*, /f*/*r/*st, /f*/*r/*e*t, /f*/*r/*es*, /f*/*r/t*t, /f*/*r/t*s*, /f*/*r/te*, /f*/*r/*t, /f*/*r/*s*, /f*/*r/*e*, /f*/*r/t*, /f*/*r/*, /f*/*a*/test, /f*/*a*/*est, /f*/*a*/t*st, /f*/*a*/te*t, /f*/*a*/tes*, /f*/*a*/*st, /f*/*a*/*e*t, /f*/*a*/*es*, /f*/*a*/t*t, /f*/*a*/t*s*, /f*/*a*/te*, /f*/*a*/*t, /f*/*a*/*s*, /f*/*a*/*e*, /f*/*a*/t*, /f*/*a*/*, /f*/b*/test, /f*/b*/*est, /f*/b*/t*st, /f*/b*/te*t, /f*/b*/tes*, /f*/b*/*st, /f*/b*/*e*t, /f*/b*/*es*, /f*/b*/t*t, /f*/b*/t*s*, /f*/b*/te*, /f*/b*/*t, /f*/b*/*s*, /f*/b*/*e*, /f*/b*/t*, /f*/b*/*, /f*/*/test, /f*/*/*est, /f*/*/t*st, /f*/*/te*t, /f*/*/tes*, /f*/*/*st, /f*/*/*e*t, /f*/*/*es*, /f*/*/t*t, /f*/*/t*s*, /f*/*/te*, /f*/*/*t, /f*/*/*s*, /f*/*/*e*, /f*/*/t*, /f*/*/*, /*/bar/test, /*/bar/*est, /*/bar/t*st, /*/bar/te*t, /*/bar/tes*, /*/bar/*st, /*/bar/*e*t, /*/bar/*es*, /*/bar/t*t, /*/bar/t*s*, /*/bar/te*, /*/bar/*t, /*/bar/*s*, /*/bar/*e*, /*/bar/t*, /*/bar/*, /*/*ar/test, /*/*ar/*est, /*/*ar/t*st, /*/*ar/te*t, /*/*ar/tes*, /*/*ar/*st, /*/*ar/*e*t, /*/*ar/*es*, /*/*ar/t*t, /*/*ar/t*s*, /*/*ar/te*, /*/*ar/*t, /*/*ar/*s*, /*/*ar/*e*, /*/*ar/t*, /*/*ar/*, /*/b*r/test, /*/b*r/*est, /*/b*r/t*st, /*/b*r/te*t, /*/b*r/tes*, /*/b*r/*st, /*/b*r/*e*t, /*/b*r/*es*, /*/b*r/t*t, /*/b*r/t*s*, /*/b*r/te*, /*/b*r/*t, /*/b*r/*s*, /*/b*r/*e*, /*/b*r/t*, /*/b*r/*, /*/ba*/test, /*/ba*/*est, /*/ba*/t*st, /*/ba*/te*t, /*/ba*/tes*, /*/ba*/*st, /*/ba*/*e*t, /*/ba*/*es*, /*/ba*/t*t, /*/ba*/t*s*, /*/ba*/te*, /*/ba*/*t, /*/ba*/*s*, /*/ba*/*e*, /*/ba*/t*, /*/ba*/*, /*/*r/test, /*/*r/*est, /*/*r/t*st, /*/*r/te*t, /*/*r/tes*, /*/*r/*st, /*/*r/*e*t, /*/*r/*es*, /*/*r/t*t, /*/*r/t*s*, /*/*r/te*, /*/*r/*t, /*/*r/*s*, /*/*r/*e*, /*/*r/t*, /*/*r/*, /*/*a*/test, /*/*a*/*est, /*/*a*/t*st, /*/*a*/te*t, /*/*a*/tes*, /*/*a*/*st, /*/*a*/*e*t, /*/*a*/*es*, /*/*a*/t*t, /*/*a*/t*s*, /*/*a*/te*, /*/*a*/*t, /*/*a*/*s*, /*/*a*/*e*, /*/*a*/t*, /*/*a*/*, /*/b*/test, /*/b*/*est, /*/b*/t*st, /*/b*/te*t, /*/b*/tes*, /*/b*/*st, /*/b*/*e*t, /*/b*/*es*, /*/b*/t*t, /*/b*/t*s*, /*/b*/te*, /*/b*/*t, /*/b*/*s*, /*/b*/*e*, /*/b*/t*, /*/b*/*, /*/*/test, /*/*/*est, /*/*/t*st, /*/*/te*t, /*/*/tes*, /*/*/*st, /*/*/*e*t, /*/*/*es*, /*/*/t*t, /*/*/t*s*, /*/*/te*, /*/*/*t, /*/*/*s*, /*/*/*e*, /*/*/t*, /*/*/*]

3) Then I loop over the items in this list above and validate if it only matches a single file-path in the input array of file-paths. (I do this by checking two things: are the amount of slashes the same, and does it match the regex where every * is replaced with .*.)
If it does: keep the (first) shortest, which we return in the end.

What's >>>? I know >> is bitwise right shift.

@Pavel For positive integers, >>> acts the same as >>. But for negative integers it changes the parity bit to 0 (you can see some examples here at the section ">> vs >>>"). -1>>>1 is just a shorter variant of Integer.MAX_VALUE (and 1<<31 would be Integer.MIN_VALUE).


text:
Are circular tapes exciting?
A Brainfuck derivative
Let's define a simple Brainfuck-like programming language.
It has a two-directional tape of cells, and each cell holds one bit.
All bits are initially 0.
There is a moving head on the tape, initially at position 0.
A program is a string over the characters <>01!, executed from left to right, with the following semantics:

< moves the head one step to the left.
> moves the head one step to the right.
0 puts 0 in the current cell.
1 puts 1 in the current cell.
! flips the current cell.

There are no loops, so a program of n characters terminates after exactly n steps.
A program is boring if all cells contain 0 at the end of execution, and exciting if there is at least one 1.
Note that the size of the tape is not specified, so depending on the implementation, it may be two-way infinite or circular.
An example program
Consider the program 1>>>!<<<<0>!>>>!.
On an infinite tape, execution proceeds as follows:
     v
00000000000000  Put 1
     v
00000100000000  Move by >>>
        v
00000100000000  Flip
        v
00000100100000  Move by <<<<
    v
00000100100000  Put 0
    v
00000100100000  Move by >
     v
00000100100000  Flip
     v
00000000100000  Move by >>>
        v
00000000100000  Flip
        v
00000000000000

At the end, all cells are 0, so this program is boring.
Now, let's run the same program on a circular tape of length 4.
v
0000  Put 1
v
1000  Move by >>>
   v
1000  Flip
   v
1001  Move by <<<< (wrapping around at the edge)
   v
1001  Put 0
   v
1000  Move by > (wrapping back)
v
1000  Flip
v
0000  Move by >>>
   v
0000  Flip
   v
0001

This time, there is a cell with value 1, so the program is exciting!
We see that whether a program is boring or exciting depends on the size of the tape.
The task
Your input is a non-empty string over <>01! that represents a program in the above programming language.
An array of characters is also an acceptable input format.
The program is guaranteed to be boring when run on an infinite tape.
Your output shall be the list of tape lengths on which the program is exciting.
Note that you only need to test the program on tapes that are shorter than the program length.
The solution with the lowest byte count in each language is the winner.
Standard code-golf rules apply.
Test cases
> : []
110 : []
1>0<! : [1]
0>>1>0<<>! : [1]
1>>>!<<<<0>!>>>! : [2, 4]
!<!<><<0>!>!<><1!>>0 : [2]
>>!>><>001>0<1!<<!>< : [1, 2, 3]
1!><<!<<<!!100><>>>! : [1, 3]
!!1>!>11!1>>0<1!0<!<1><!0<!<0> : [3, 4]
<><<>>!<!!<<<!0!!!><<>0>>>>!>> : [1, 2, 4]
0>>><!<1><<<0>!>>!<<!!00>!<>!0 : [3]
0000!!!!><1<><>>0<1><<><<>>!<< : []
!>!>!>!>!>1>!>0<!<!<!<0<!<0<!<!<!<1>!>0<<! : [1, 2, 5, 7]
<!!>!!><<1<>>>!0>>>0!<!>1!<1!!><<>><0<<!>><<!<<!>< : [1, 2, 4, 5]
!>1<<11<1>!>!1!>>>0!!>!><!!00<><<<0<<>0<<!<<<>>!!> : [1, 2, 3, 5, 6]

Can we choose any distinct and consistent characters instead of <>01!?

Is an array of instructions an acceptable input?

@Mr.Xcoder No, you should use these exact characters.

@Arnauld An array of characters is close enough to a string, I'll allow it.

Haskell, 119 bytes
t#'<'=last t:init t
(h:t)#c|c<'#'=1-h:t|c>'='=t++[h]|1<2=read[c]:t
f p=[n|n<-[1..length p],sum(foldl(#)(0<$[1..n])p)>0]

Try it online!
Function # is the interpreter for a single command c. The whole program p is run by folding # with the starting tape into p. f executes p for every tape and keeps those where the sum of the cells is at least 1.

n<-[1..length p]  ... 0<$[1..n] seems quite long, there must be a shorter way.

I can't see a shorter way. The problem I see is that you actually need the value of n as the result, so if you constructed 0<$[1..n] a different way (say with scanr(:)), you'd need to take the length of it. (I also tried using 1 (to replace length with sum) or False (to use or for the test) instead of 0, but it didn't come out shorter.)

@ØrjanJohansen: yes, I tried n<-init$scanr(:)[]$0<$p  ... n which is 2 bytes shorter, but it returns a list of starting tapes instead of their length, e.g.[[0],[0,0,0]]. With a little bit of rule bending so could see the tapes as unary numbers, so maybe it's ok.

init$ can be replaced by putting a [0] as initial list, but it still didn't get short enough. I think unary is only allowed for languages without a more natural number representation.

Stax, 56 54 43 38 35 bytesCP437
è¥%►BΣ░ÜY⌂y(â&.═ªê►V½▲y▌)▀♫♂╣ª?√»!#

42 bytes when unpacked,
%fz(y{{|(}{|)}{B!s+}{0_]e&}4ls"><! "I@!F|a

Run and debug online!
-2 bytes per comment by @recursive
Explanation
I will use the version with a prefix i(i.e. i%fz(y{{|(}{|)}{B!s+}{0_]e&}4ls"><! "I@!F|a) to explain and I will explain why the i can be removed
i               Suppress implicit eval
                    This prevents the test case "110" from being interpreted as a number
                    However, this can be removed because a program containing only numbers cannot be exciting and the output will be empty anyway.
                    This is based on the fact that the program is boring on non-circular tapes
 %f             Filter range [1..n] with the rest of this program
                    Where n is the length of the input
                    Implicit output the array after filtering, one element per line
   z(           Initialize the tape
     y{  F      Run the program
          |a    Any cell is non-zero

Code for running the program:
{|(}                                 Block to rotate left by one element
    {|)}                             Block to rotate right by one element
        {B!s+}                       Block to perform logical not on the element at index 0
              {0_]e&}                Block to obtain current instruction,
                                         Convert it to a number
                                         And assign to element at index 0

                     4l              Pack the 4 blocks in an array
                       s"<>! "I      Find the index of current instruction in string, if not found, the index will be -1
                                         And when indexed with -1, it wraps around to the 4th element.

                               @!    And execute the corresponding block.

I added a test case of all digits to validate your i check.

0]* can be replaced with z(.  Also, if you change the string to "<>!", then 0 and 1 will give index -1, so that way your block list only needs 4 blocks, instead of 5.  This will work since the 0 and 1 handlers are identical anyway.

@recursive Good point taken.

CJam, 57 56 49 46 bytes
-7 thanks to @MartinEnder
{:T,({)0a*T{i23%")!+(+ W0tW1t)\+"3/=~}/:+},:)}

Try it online!

Perl 5, 83 82 79 77 bytes
Includes +3 for -F
Give instructions as one line on STDIN
#!/usr/bin/perl -F
1~~@$m&&say$m until++$m>map{*r=\$$m[($n+=/>/-/</)%$m];$r=/\d/?$&:$r^/!/}@F

Try it online!

Flags now count as part of the language instead of scoring.

JavaScript (ES6), 126 118 bytes
Saved 3 bytes thanks to @user71546
Takes input as an array of 1-character strings.
f=(s,l=0,p=0,t=[])=>s[l++]?s.map(c=>1/c?t[p%l]=+c:c>'='?p++:c>';'?p+=l-1:t[p%l]^=1)&&+t.join``?[l,...f(s,l)]:f(s,l):[]

Try it online!

Replacing t.some(x=>x)? by +t.join``? instead check the array as digits (and 0 indicates an all-zero tape), but 3 bytes less.

[] can be t, it's unused on this path

Init value of p doesn't matter

Python 2, 139 135 133 132 131 bytes
-3 bytes thanks to Mr. Xcoder

def f(p):i=0;exec"i+=1;s=[0]*i\nfor c in p:c=ord(c)-61;s=c>-2and s[c:]+s[:c]or[[s.pop(0)^1,0,1][c%7]]+s\nif 1in s:print i\n"*len(p)

Try it online!

131 bytes?

Perl 5 (-F), 101 bytes
map{$,=@a=(0)x$_;map{$,+=/>/-/</;$a[$,%@a]=$&if/0|1/;$a[$,%@a]=!$a[$,%@a]if/!/}@F;say if@a~~/1/}1..@F

Try it online!

Red, 243 bytes
func[p][repeat n length? p[b: copy[]insert/dup b 0 n i: 1
parse p[any["<"(i: i - 1 if i < 1[i: n])|">"(i: i + 1 if i > n[i: 1])|"0"(b/(i): 0)|"1"(b/(i): 1)|"!"(b/(i): either b/(i) = 0[1][0])|
skip]]s: 0 foreach c b[s: s + c]if s > 0[print n]]]

Try it online!
Prety verbose and straightforward implementation. Red's 1-indexing doesn't allow me to reduce the byte count by using modular arithmetic for looping through the circular tapes.
Ungolfed
f: func[p][
    repeat n length? p[
        b: []
        insert/dup b 0 n
        i: 1
        parse p[
            some [
                 "<" (i: i - 1 if i < 1[i: n])
               | ">" (i: i + 1 if i > n[i: 1])
               | "0" (b/(i): 0)
               | "1" (b/(i): 1)
               | "!" (b/(i): either b/(i) = 0 [1][0])
               | skip
            ]
        ]
        s: 0
        foreach c b[s: s + c]
        if s > 0 [print n]
    ]
]

APL (Dyalog Unicode), 79 64 54 bytes (Adám's SBCS)
⍸⊂{∨/⍎⍕(↓',',⍨5 3⍴'0@11@1~@1 1⌽¯1⌽')['01!<'⍳⌽⍺]⍵}¨0=,\

Try it online!
-15 thanks to Adám (forgot about monadic ⍸).
-10 thanks to ngn.

64

@Adám Hm, looks like that's not optimal (for example you don't need the ↓). I'll look into it and update. :)

But if you remove the ↓ you'll need a ;, no?

@Adám no, why would you?

Because rank-2 arrays need two index parts.

@Adám Uh, I did the change on the wrong function. >< (also why did I use '⊢,' instead of ,, while , already separates >>>__<<<)

so many opportunities for improvement: ⍸⊂{∨/⍎⍕(↓',',⍨5 3⍴'0@11@1~@1 1⌽¯1⌽')['01!<'⍳⌽⍺]⍵}¨0=,\

@ngn yeah, looks like "opportunities" has a different meaning for the rest of us :P

Retina, 121 bytes
.+
$.&*0¶$&
\G0
0$`¶
{ms`^.(?=.*¶¶(0|1))
$1
"¶¶!"&mT`d`10`^.
"¶¶>"&`(.)(.*)¶
$2$1¶
"¶¶<"&`(.*)(.)¶
$2$1¶
)`¶¶.
¶¶
G`1
%`.

Try it online! Explanation:
.+
$.&*0¶$&
\G0
0$`¶

Create an array of tapes of each length up to the length of the input program.
{

Loop until the program is consumed.
ms`^.(?=.*¶¶(0|1))
$1

If the next character in the program is a 0 or 1, change the first character on each line to that character.
"¶¶!"&mT`d`10`^.

If it is a ! then toggle the first character on each line.
"¶¶>"&`(.)(.*)¶
$2$1¶
"¶¶<"&`(.*)(.)¶
$2$1¶

If it is a > or < then rotate the line. (Easier than moving the head.)
)`¶¶.
¶¶

Delete the instruction and end the loop.
G`1

Keep only the exciting lines.
%`.

Count the length of each line.

MATL, 46 39 bytes
f"@:~G"@59>?@61-YS}@33=?t1)~}@U]1(]]a?@

Try it online! Or verify all test cases.
How it works
f             % Push indices of nonzero chars of (implicit) input string: gives
              % [1 2 ... n] where n is input length
"             % For each k in [1 2 ... n]. These are the possible tape lengths
  @:~         %   Push array of k zeros. This is the tape, in its initial state
  G           %   Push input string
  "           %   For each char in the input string
    @59>?     %     If code point of current char exceeds 59 (so it is '<' or '>')
      @61-    %       Push code point minus 61: gives -1 for '<', or 1 for '>'
      YS      %       Circularly shift the tape by that amount. Instead of moving
              %       the head, we shift the tape and keep the head at entry 1
    }         %     Else
      @33=?   %       If code point of current char is 33 (so it is '!')
        t1)   %         Duplicate the array representing the tape, and get its
              %         first entry
        ~     %         Logical negate
      }       %       Else
        @U    %         Push current char (it is '0' or '1') converted to number
      ]       %       End
      1(      %       Write (either 0, 1 or old value negated) at entry 1
    ]         %     End
  ]           %   End
  a?          %   If the tape contains at least a nonzero value
    @         %     Push tape length, k
              %   End (implicit)
              % End (implicit)
              % Display (implicit)

APL (Dyalog Unicode), 192 78 bytes
⊂{t/⍵⊣⍵{t[m]←('01!'⍳⍵)⊃0 1,e,⍨~e←t[m←⍺|i⊣i+←¯1 1 0⊃⍨'<>'⍳⍵]}¨⍺⊣i←⊃t←⍬⍳⍺}¨1+⍳∘≢

Try it online! (non-flattened result)
Try it online! (flattened)
After some time spent banging my head against the wall, I decided to make a Tradfn instead of a Dfn. This is the result. Smarter people than me may be able to golf the heck out of this.
Surprise, surprise, someone smarter than me did golf the heck out of this. Thank you Adám for 114 bytes.
He said:

Notice that it is your exact program, except using indexing instead of the inner :Ifs and collapsing :For-loops to {_}¨ while giving a left argument to replace the global.

The function assumes ⎕IO←0.

How?
(This explanation uses an "ungolfed" version to facilitate reading)
⊂{                                  ⍝ Enclose
      i←⊃t←⍬⍳⍺                      ⍝ Assign a vector of 0s to t (the tape), then assign the first 0 to i.
      t/⍵⊣⍵{                        ⍝ Use ⍵ as left argument for the nested function, then compress the result into t. If there is a 1 anywhere in t, the result will be a vector of the result. If not, the result is an empty vector.
          i+←¯1 1 0⊃⍨'<>'⍳⍵         ⍝ Map the string '<>' to the argument (which is the BF program). That yields 0 for <, 1 for >, and 2 for anything else.
                                    ⍝ The resulting vector will then be used as the argument for ⊃ to add -1 (index 0), 1 (index 1) or 0 (index 2) to the variable i.
          e←t[m←⍺|i]                ⍝ Assign i mod ⍺ (left arg) to m, and use it to index t. Then, assign the value to e.
          t[m]←('01!'⍳⍵)⊃0 1,e,⍨~e  ⍝ Map the string '01!' to ⍵. As before, this yields 0 for 0, 1 for 1, 2 for ! and 3 for anything else.
                                    ⍝ Then, concatenate (not e) with e, then concatenate that with the vector 0 1. This is used as argument to be picked from, and it is assigned to t[m].
      }¨⍺                           ⍝ Do that for each argument
  }¨1+⍳∘≢                           ⍝ And do that for each possible tape length from 1 to the length of the input.

Save one byte by making t←l⍴0 be t←l⍴i←0, and removing the line above it. You can also save another by changing t[i|⍨≢t]←1-t[i|⍨≢t] to t[i|⍨≢t]←~t[i|⍨≢t].

@Zacharý right, and further save an additional 112 bytes. Exactly same code, just golfed a bit.

Yeah, it's just goled "a bit". Don't you need the ∇s?

@Zacharý What ∇s? It is a tacit function.

@Zacharý I would consider this one pretty Adám'd, wouldn't you?

That comment was BEFORE @J.Sallé updated it, and it's been Erik'd, Adám'd, and then Adám'd again...

Jelly, 41 bytes
JR0ṁð3“1⁺¦01¦¬1¦ṙ1 ṙ- ”s“10!<>”,yẎvÐ€⁸Ẹ€T

Try it online!

C (clang), 171 bytes
l,i;f(S){for(char*p,t[l=strlen(S)];l;memchr(t,1,l)&&printf("%d ",l),l--)for(memset(t,i=0,l),p=S;*p;p++)*p==60?i=i?i-1:l-1:*p==62?i=i^l-1?i+1:0:*p^33?t[i]=*p-48:(t[i]^=1);}

Try it online!
Had to use clang, since using char*p,t[l=strlen(S)] as the initialisation expression for some reason makes GCC think I want to declare strlen instead of calling it.
Pretty straight-forward: Runs the program on circular tapes of decreasing length, outputting any length that resulted in a 1 somewhere on the tape.
Tried shortening the tangle of the ternary operators, but ended up needing more parenthesis than was healthy.

Suggest i=0,bzero(t,l) instead of memset(t,i=0,l) and *p-62?t[i]=*p^33?*p-48:t[i]^1:(i=~i+l?i+1:0) instead of *p==62?i=i^l-1?i+1:0:*p^33?t[i]=*p-48:(t[i]^=1)

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
Tips for golfing with numpy, scipy, or pylab
There's already a comprehensive list of tips for python here, so what I'm asking for are tips that specifically apply to using the numpy, scipy or pylab libraries.
These can be either ways to shorten code already using numpy, or ways to shorten common python operations by using these libraries.
One tip per answer, please.

Note that pylab is just matplotlib.pyplot + numpy in a deprecated common namespace. The numpy part of pylab is trivial in the sense that their imports have the same number of bytes, so only plotting stuff could additionaly come from pylab, but I suspect that's not what you had in mind with your question.

@AndrasDeak, I'm aware that using pylab is considered bad practice, but very little in codegolf can be considered good practice. Pylab directly includes parts of many numpy packages.  For example pylab.randint is valid where numpy would require numpy.random.randint.  So for golfing pylab should provide shorter code.

I'm aware that deprecation is not a problem, my point was that it also doesn't give an advantage. I simply didn't realize that subpackages were also loaded into the pylab namespace like that! So sorry, you're perfectly right :)

Make use of Numpy's broadcasting
Broadcasting means replicating a multidimensional array along some of its singleton dimensions to match the size of another array. This happens automatically for Numpy arrays when arithmetic operators are applied to them.
For example, to generate a 10×10 multiplication table you can use
import numpy
t=numpy.arange(1,11)
print(t*t[:,None]) # Or replace t[:,None] by [*zip(t)]

Try it online!
Here t is created as the Numpy array [1, 2, ..., 10]. This has shape (10,), which is equivalent to (1,10). The other operand array, t[:,None], has size (10,1). Multiplying the two arrays implicitly replicates them, so they behave as if they both had shape (10,10). The result, which also has shape (10,10), contains the products for all pairs of entries in the original arrays.

That was a clever use of zip with the broadcasting, is that going to come up in it's own answer?

@user2699 I don't think it's worth a separate answer, because [*zip(t)] has the same byte count as the more readable t[:,None]. But you are right, it may be worth noting, so I added it back here

Good point, I guess I didn't actually count the bytes.  [*zip(t)] would be two bytes shorter if there were more dimensions.

Note that extended iterable unpacking in [*zip(t)] will only work on python 3.

I viewed this page as I am interested in finding out what numpy has that Perl 6 doesn't. Anyway that would be written as my \t = 1..10; .fmt('%3d').put for t «*» t[*,Empty] or you could use zip(t)

Use r_[...] instead of range(...)
Numpy provides matlab like syntax for array creation using r_[...].  Any slice notation in between the brackets is interpreted as an array with the range indicated.  So, for instance
r_[:30:4]

is equivalent to
arange(0,30,4)

and for most uses can replace
range(0,30 4)

It can also handle more complex expressions.
For example to get indices from 0 up to 10 and back down again,
r_[:10,10:-1:-1]

The shorter than shortest infinite for comprehension
If numpy is *-imported then using this "feature" of numpy.r_/numpy.c_ an infinte counter is as cheap as:
for[i]in r_:print(i)

This is significantly shorter than this pure Python trick and has the added benefit of actually creating a proper counter.
This can also be used for a cheaper enumerate:
S="abcde"
for x,[i]in zip(S,r_):print(i,x)

If you can live with a "boxed" counter, i.e. [0],[1],[2],... rather than 0,1,2,... then you can save the brackets around i.
The boxes can even be useful: For example, if we have set up a loop anyway, then we can as a byproduct create a reversed "range" of the same length as the looped over sequence S:
C=[]
for e,C[:0]in zip(S,r_):f(e)

If for some reason you need double boxes [[0]],[[1]],[[2]],... use c_ instead of r_.

Don't forget the matrix class
It may be aesthetically challenged and semi-deprecated since all but forever but it can be useful for golfing.
Here is an example How to solve the LCM in 50 bytes of Python where on a non numpy specific challenge it allows us to outgolf @dingledooper's extremely clever pure Python approach by ~10%. And that's counting the numpy import and without requiring us to be particularly smart:
from numpy import*
print(lcm(*mat(input()).A1))

Try it online!
This shows off three useful features:

Short constructor name mat although not as short as r_ or c_

Hilariously graceful input parser. For example, it will accept

mat("""[1 2]\t[3,4];5  6 7
8""")

without complaint.

a handful of very short-named attributes, viz. A,A1,T,H,I which are the underlying array object,the same flattened,the transpose,the conjugate transpose and the pseudo inverse.

Finally, there is one more useful feature that we didn't use in the example:

Overloaded * operator. That in itself doesn't gain us much over the @ operator for standard numpy arrays but for example taking the matrix power can be done using ** much shorter than linalg.matrix_power.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Quickly regrouping lists
Grouping takes a list and splits it into new lists of equal adjacent elements.  For example
[1,1,2,1,1] -> [[1,1],[2],[1,1]]

If you then take the length of these groups you get a new list of integers
[1,1,2,1,1] -> [2,1,2]

Your task is to write a program that takes a list of positive integers and find the number of times you can group and length it before the resulting list has a single element.  For example the list [1,2,3,3,2,1] can be regrouped 4 times
[1,2,3,3,2,1]
[1,1,2,1,1]
[2,1,2]
[1,1,1]
[3]

This is code-golf so answers will be scored in bytes with fewer bytes being better.
Test cases
[1,2,3,3,2,1] -> 4
[1,2,3,4,5,6,7] -> 2
[1,1,1,1,1,1] -> 1
[2] -> 0
[1,2,4] -> 2
[1,2,2,1,1,2] -> 4
[1,2,2,1,1,2,1,2,2] -> 5
[1] -> 0

This is basically run-length encoding without storing the values.

[1] is a valid input and should give 0, correct?

@ETHproductions Yes, I'll add that because it is a bit of a tricky case.

The whole task is precisely the definition of runs-resistance. Related OEIS sequence: A318928 - Runs-resistance of binary representation of n

Haskell, 49 bytes
import Data.List
f[_]=0
f c=1+f(length<$>group c)

Try it online!

CJam, 18 bytes
q~_,{_e`0f=}*]:,1#

Try it online!

Brachylog, 12 bytes
;.{ḅlᵐ}ⁱ⁾l1∧

Try it online!
Explanation
;.{   }ⁱ⁾        Iterate Output times the following predicate on the input:
   ḅ               Group consecutive equal elements together
    lᵐ             Map length
         l1∧     The result of this iteration must have length 1

Japt, 12 bytes
ÊÉ©1+ßUò¦ ml

Test it online!
Explanation
 Ê É © 1+ßUò¦  ml
Ul -1&&1+ßUò!= ml    Ungolfed
                     Implicit: U = input array
Ul -1                Take U.length - 1.
     &&              If this is non-zero:
          Uò!=         Split U between non-equal elements.
               ml      Take the length of each run of equal elements.
         ß             Run the entire program again on the resulting array.
       1+              Add one to the return value.

Recursion is a really non-conventional approach for Japt, but it seems to be 4 bytes shorter than the next alternative...

@Shaggy My 16-byte version with F.a() is still accessible through the revision history. I'd love to see your 14-byter though!

K (oK), 20 19 bytes
Solution:
#2_{#:'(&~~':x)_x}\

Try it online!
Examples:
#2_{#:'(&~~':x)_x}\1 2 3 3 2 1
4
#2_{#:'(&~~':x)_x}\1 2 3 4 5 6 7
2
#2_{#:'(&~~':x)_x}\1 1 1 1 1 1
1
#2_{#:'(&~~':x)_x}\1#2
0
#2_{#:'(&~~':x)_x}\1 2 4
2

Explanation:
This one is pretty simple, am wondering if there is an even better approach though... Find the indices where the input differs, split at those indices and then count the length of each sub-list. Iterate until results converge to 1.
#2_{#:'(&~~':x)_x}\ / the solution
   {             }\ / scan over lambda until results converge
                x   / implicit input
               _    / cut at indices
       (      )     / do this together
         ~~':x      / differ... not (~) match (~) each-previous (':) x)
        &           / indices where true
    #:'             / count (#:) each (')
 2_                 / drop first two results
#                   / count result

Notes:
The following 14 byte solution works for all except a single-item list:
#1_(-':&~~':)\

Try it online!

Husk, 8 bytes
-1 byte thanks to @Zgarb!
←Vε¡(mLg

Try it online!
Explanation
←Vε¡(mLg)  -- example input: [1,2,3,3,2,1]
   ¡(   )  -- repeatedly apply the function & collect results
    (  g)  -- | group: [[1],[2],[3,3],[2],[1]]
    (mL )  -- | map length: [1,1,2,1,1]
           -- : [[1,2,3,3,2,1],[1,1,2,1,1],[2,1,2],[1,1,1],[3],[1],[1],...
 V         -- index where
  ε        -- | length is <= 1: [0,0,0,0,1,1...
           -- : 5
←          -- decrement: 4

←Vε is a shorter check for finding the singleton list's index.

J, 25 23 bytes
1 byte saved thanks to streetster
1 byte saved thanks to FrownyFrog
2#@}.#;.1@(0,2=/\])^:a:

Try it online!
Initial solution:
_2+[:#(#;.1~1,2~:/\])^:a:

Try it online!
Explanation
      (               )^:a: - repeat until result stops changing, store each iteration
        ;.1~                - cut the input (args swapped)
            1,2~:/\]      - where the items are no longer the same
       #                    - and take the length of the sublists
 2+[:#                      - finally subtract 2 from the number of steps

Can you do 'drop two' then 'count' rather than _2+ to save a byte?

I think #;.1@(0,2=/\]) saves 1 byte.

@ FrownyFrog Yes, it does. Thank you!

@streetster Yes, It helps to save a byte. Thank you!

C (gcc), 108 103 bytes

Saved five bytes thanks to ceilingcat.

j,k,n;f(A,l)int*A;{for(j=k=n=0;j<l;j++)n=A[j]-A[k]?A[k++]=n,A[k]=A[j],1:n+1;A=l>1?-~f(A,k,A[k++]=n):0;}

Try it online!
Explanation (108 bytes version)
j,k,n;                // array pos, group pos, group val
f(A,l)int*A;{         // function takes array and length
 for(j=k=n=0;j<l;j++) // initialize, loop through array
  if(n++,             // increase n (*), check if group ended
  A[j]-A[k])          // group ended
   A[k++]=--n,        // advance group pos, decrease n, counteracting (*)
   A[k]=A[j],         // store new group type
   n=1;               // group is at least one long
 A=l>1?               // check if array length is larger than one
  -~f(A,k,A[k++]=n)   // fix last group length, enter recursion
  :0;}                // array length is less than two, return zero

Try it online!

JavaScript (ES6), 67 65 63 bytes
f=a=>a[1]?1+f(q=j=i=[],a.map(x=>x^a[++i]?j=!q.push(++j):++j)):0

Oddly enough, JavaScript and Japt seem to have the same shortest algorithm for once...

Stax, 9 bytes
ÆÑfá╒]`*Ä

Run and debug it online
The ascii representation of the same program is this.
{D}{|RMHgf%

This uses a stax feature called a generator that produces value according to transformation and filter blocks.
{ }            the filter for the generator
 D             tail of array; this is truthy for length >= 2
   {    gf     generator block - termination condition is when the filter fails
    |R         run-length encode into pairs [element, count]
      M        transpose matrix
       H       last element
          %    length of final generated array

APL (Dyalog Unicode), 33 24 bytes
Saved 9 bytes thanks to @Adám!
{1=≢⍵:0⋄1+∇2-/⍸2≠/0,⍵,0}

Try it online!
{
 1=≢⍵           ⍝If the length (≢) of the input (⍵) is 1
  :0            ⍝return 0, as we can't go further

⋄1+             ⍝Otherwise, add 1 to the result of the next call:
  ∇2-/⍸2≠/0,⍵,0 ⍝Next step
         0,⍵,0  ⍝ Put 0s on both sides (1 1 1 2 2 1 -> 0 1 1 1 2 2 1 0)
      2≠/       ⍝Pairwise reduce with ≠
                ⍝0 1 1 1 2 2 1 0 -> 1 0 0 1 0 1 1
                ⍝There is now a 1 wherever a run starts
      ⍸          ⍝Indices of 1s (indices where runs start)
                ⍝1 0 0 1 0 1 1 -> 1 4 6 7
   2-/          ⍝Pairwise reduce with subtraction (length of each run)
                ⍝1 4 6 7 -> 3 2 1
 ∇              ⍝Call itself with new list
}
```

2f/ can really help here. Spoiler.

@Adám Wow, that's a lot shorter!

Jelly, 10 bytes
ŒgL€$ḊÐ¿L’

Try it online!

This fails for [1]. You should be able to fix it using two dequeues / pops instead of _2

ÐĿ wasn't a good choice in the first place... Replaced it with a while loop.

CJam, 19 bytes
q~{_);}{_e`0f=}w],(

Try it online!

CJam, 20 bytes
l~{__,(}{e`z0=}w;;],

Try it online!

SmileBASIC, 110 108 bytes
DEF R L,J
K=LEN(L)FOR I=1TO K
N=POP(L)IF O-N THEN UNSHIFT L,0
INC L[0]O=N
NEXT
IF I<3THEN?J ELSE R L,J+1
END

Call function as R list,0; output is printed to the console.

Python 2, 84 bytes
f=lambda a:len(a)>1and-~f(eval(''.join('1'+',+'[x==y]for x,y in zip(a,a[1:]))+'1,'))

Try it online!
How?
f is a recursive function which, if its input, a, has length 2 or more  (len(a)>1) returns 1+f(x)* where x is the group lengths of a; while if its input is length 1 or 0 returns False (equal to 0 in Python) - this is because the right hand side of the and does not get evaluated when the left is falsey.
* -~f(x) is -(-1 - f(x)) but can abut the and unlike 1+f(x) or f(x)+1)
The group lengths are calculated by creating code which is then evaluated with eval(...). The code created is something like 1,1,1+1+1,1,1+1,1, which evaluates to a tuple like (1,1,3,1,2,1).
The code is created by zipping through a and a without its head (...for x, y in zip(a,a[1:]) making x and y each of the adjacent pairs in a. If the pair are equal x==y evaluates to True (1) otherwise False (0) - this result is used to index into the string ,+  yielding + and , respectively and each resulting character is preceded by a 1 ('1'+...) - the whole thing then has a final, trailing 1, appended. For example if a were [5,5,2,9,9,9] then the x,y pairs would be (5,5)(5,2)(2,9)(9,9)(9,9) making the equalities 10011 then the characters would be +,,++, which with the preceding 1s becomes 1+1,1,1+1+ and the final trailing 1, making 1+1,1,1+1+1, which evaluates to (2,1,3) as required.
Note that the trailing , ensures that an input with a single group is evaluated as a tuple rather than an integer (i.e. [3,3] -> 1+1, -> (2) rather than [3,3] -> 1+1 -> 2)

Perl 6, 52 bytes
{+($_,*.comb(/(\d+)[" "$0»]*/).map(+*.words)...^1)}

Test it
Expanded:
{  # bare block lambda with implicit parameter ｢$_｣

  + (              # turn the following into a Numeric (get the count)

      $_,          # seed the sequence with the input

      *.comb(      # turn into a string, and grab things that match:

        /          # regex
          ( \d+ )  # a run of digits (number)
          [
            " "    # a space
                   # (gets inserted between elements of list when stringified)

            $0     # another instance of that number
            »      # make sure it isn't in the middle of a number

          ]*       # get as many as possible
        /
      ).map(
        +*.words  # turn each into a count of numbers
      )

      ...^        # keep doing that until (and throw away last value)

      1           # it gives a value that smart-matches with 1
                  # (single element list)
  )
}

Wolfram Language (Mathematica), 32 bytes
Saved 2 bytes thanks to Martin Ender. Using CP-1252 encoding, where ± is one byte.
±{_}=0;±x_:=1+±(Length/@Split@x)

Try it online!

Defining  an operator saves two bytes: ±{_}=0;±x_:=1+±(Length/@Split@x) (assuming WindowsANSI encoding)

Perl 5, 53 50 49 45 bytes
Includes +3 for -p
Give the list of numbers as one line on STDIN
#!/usr/bin/perl -p
s%%$\+=1<s:\d+:$.++x($'-$&and$.=1):eg%eg}{

Try it online!

Ruby, 54 56 55 54 bytes
g=->l,d=0{l[1]?g[l.chunk(&:i).map{|i,j|j.size},d+1]:d}

Try it online!

05AB1E, 9 bytes
[Dg#γ€g]N

Try it online!
Explanation
[Dg#   ]     # loop until the length of the current value is 1
    γ        # split into groups of consecutive equal elements
     €g      # get length of each
        N    # push the iteration variable N

Jelly, 6 bytes
ŒɠƬṖṖL

Try it online!
I assume that Œɠ did not exist when Dennis wrote his solution, and it wouldn't surprise me if this challenge had even inspired him to add it, but it's worth showing that this solution is possible now.

Python 2, 85 bytes
from itertools import*
f=lambda a:~-len(a)and-~f([len(list(v))for k,v in groupby(a)])

Try it online!

R, 51 45 bytes
f=function(a)"if"(sum(a|1)>1,f(rle(a)$l)+1,0)

Try it online!
Recursively take the length of the run length encoding and increment the counter.

Retina 0.8.2, 31 bytes
,.*
$&_
}`(\b\d+)(,\1)*\b
$#2
_

Try it online! Link includes test cases. Explanation:
,.*
$&_

If there is a comma, we're going to make another iteration, so append a count character.
}`(\b\d+)(,\1)*\b
$#2

Replace each run with its decremented length. The above stages repeat until there are no commas left.
_

Count the number of iterations.

Brain-Flak, 78 bytes
({}<>)<>({()<(<>{}<(())><>){({}[({})]<>){((<{}>))}{}((){})<>}<>{}({}<>)<>>}{})

Try it online!

Pyth, 9 bytes
ltt.uhMr8

Test suite!

Red, 140 bytes
func[b][n: 0 while[(length? b)> 1][l: copy[]parse split form b" "[any[copy s[set t string! thru any t](append l length? s)]]b: l n: n + 1]n]

Try it online!
I just wanted to give Red's Parse dialect another try.
Ungolfed
f: func [b] [
    n: 0
    while [(length? b) > 1][
        l: copy []
        parse split form b " " [
            any [copy s [set t string! thru any t]
                (append l length? s)]
        ]
        b: l
        n: n + 1
    ]
    n
]


text:
Given a number, print out its "collective sum"
Given a number as input, print out its collective sum
What is a collective sum?
Consider the number 13214, the input
Looping through each of the digits starting from the left, we will be able to obtain its collective sum.
1 means look at the first digit, and add it to the sum, sum = 1
3 means look at the "first 3 digits" and add it to the sum, sum = 1 + 132
2 means look at the "first 2 digits" and add it to the sum, sum = 1 + 132 + 13
1 means look at the first digit, and add it to the sum, sum = 1 + 132 + 13 + 1
4 means look at the "first 4 digits" and add it to the sum, sum = 1 + 132 + 13 + 1 + 1321
Total sum = 1468 and this is your output

Special cases:

If we encounter a 0, then clearly we keep the sum the same
The number 1301 would have a sum = 1 + 130 + 1 = 132

If we encounter a number that is larger then the length of the input, we add it all
The number 251 would have a sum = 25 + 251 + 2 = 278

Test cases:

collectiveSum(0) = 0

collectiveSum(2) = 2

collectiveSum(2315) = 23 + 231 + 2 + 2315 = 2571

Shortest amount of bytes wins. Happy golfing!

As is often a question with these kinds of tasks: May we accept a list of the digits as our input?

The 2315 test case is missing the + 2 from the 1 and should result in 2571.

Do we expect to have to deal with inputs starting with 0 aside from 0? How should the program deal with these inputs

It looks like the last test case is wrong; should be 2571.

I don't see why the input should be a number rather than a list of integers.  It seems like an unnecessarily cumbersome form of input.

I'm not sure what kinds of inputs are allowed, can I take a list of integers as input?

I'd recommend against accepting answers at all (see here), but if you do want to have an accepted answer, I'd wait about a week, so that the competition still seems open.

@cairdcoinheringaahing I'll keep this in mind

05AB1E,  4  3 bytes
-1 thanks to Kevin Cruijssen (use of € avoiding a })
€£O

Try it online!
How?
€£O - implicit input   e.g. 2315
€   - map with:
 £  -   head to             23, 231, 2, 2315
  O - sum                   2571

Beat me by 13 seconds xD

Glad I waited to add the link to bytes then :p

ε£} can be €£ to save a byte.

@KevinCruijssen was that also an option when I created this?

@JonathanAllan Not entirely sure, but I think it indeed already was. Adnan started writing the Elixir rewrite in the Summer of 2018 (which was released in August), and € was already there for quite a while in the legacy version of 05AB1E before that. It was already there when I posted my very first 05AB1E answer in April 2018. So it might be possible it was added shortly after you posted this answer, but I'm not sure.

@KevinCruijssen it looks like it did. Thanks!

Python 2, 43 bytes
lambda n:sum(int('0'+n[:int(x)])for x in n)

Try it online!

Unfortunately this appears to raise a ValueError for input of 1301, or any input that has a zero as one of its digits.

@mathmandan Should be fixed now?

The int function can accept an integer, replacing the '0' string literal with just 0 should shave off one byte.

@MooseOnTheRocks Did in a way that seems less hacky-looking (?) to me, unless I'm stupid and messed something up (usually)

Python 2, 72 bytes
First submission! Thanks to @DestructibleLemon for the help!
import sys;d=sys.argv[1];s=0;for e in d:s+=int(d[:int(e)]);print str(s)

Just so you know, the downvote seems to have been given automatically by the community user when I edited the header of your post. Sorry. It's an annoying, nonsensical feature. Though I don't know why it did that this time, because as far as I can tell, this was not flagged as low-quality.

Welcome to PPCG! Nice first submission! And yeah, as Steadybox said, the downvote was automatically placed for no good reason in particular. Your post has gotten a few upvotes so hopefully at the next cron job the automatic downvote should be removed :)

Haskell, 43 37 bytes
f l=sum[read$'0':take(read[d])l|d<-l]

Try it online!
The input number is taken as a string.
   [        |d<-l]      -- for every digit d in the input string
        read[d]         -- convert to a number
      take     l        -- and take that many digits from l
     0:                 -- prepend a 0 (to handle 0s)
   read                 -- convert to a number
sum                     -- sum all numbers

Ruby, 36 bytes
->n{n.sum{|x|n[0,x.to_i].join.to_i}}

Try it online!

#sum isn't defined on fixnums, so I assume you want n to be a string. However, String#sum computes a not a particularly good checksum and ignores the block you give it. If you meant n.chars.sum{, Enumerable#sum isn't in the ruby stdlib, it's an extension provided by rails. Please test your solutions before posting them.

@Shelvacu Yeah, I'm taking input as an array though... see the footer provided. Plus Enumerable#sum is in Ruby 2.4, and TIO uses 2.4

31 bytes if you take an array of digits as input

@AsoneTuhid I don't think that's a valid form of input, if you find evidence otherwise please explain

This page doesn't seem to address the issue but i don't see a list of integers as being too different from a list of characters (which is what your answer takes as input)

JavaScript, 42 40 bytes
Thanks @Shaggy for golfing off 2 bytes

f=
x=>[...x].map(y=>a+=+x.slice(0,y),a=0)|a

console.log(f("2315"))
console.log(f("0100"))
console.log(f("2"))
console.log(f("01025"))

Receives input as a string and returns an integer. As currently written, this code leaves leading zeroes on any integers.

40 bytes: x=>[...x].map(y=>a+=+x.slice(0,y),a=0)|a

R, 57 bytes
saved one more thanks to @Vlo
sum(strtoi(substring(i<-scan(,""),1,el(strsplit(i,"")))))

was:
Saved 4 bytes thanks to @Robert Hacken's suggestion.
i=scan(,"");sum(strtoi(substring(i,1,el(strsplit(i,"")))))

A simple string approach.

You can save 4 bytes replacing unlist by el.

Save 1 with inline assignment sum(strtoi(substring(i<-scan(,""),1,el(strsplit(i,"")))))

C (gcc), 106 bytes
j,k,c,t;f(char*S){for(t=j=0;S[j];j++)c=S[k=S[j]-48<(c=strlen(S))?S[j]-48:c],S[k]=0,t+=atoi(S),S[k]=c;S=t;}

Try it online!

Jelly,  7  5 bytes
-2 thanks to Dennis (head vectorises >.<)
4 if we may take lists of digits*
Dḣ`ḌS

Try it online!
* ḣ`ḌS
How?
Dḣ`ḌS - Link: integer, n   e.g. 2315
D     - to decimal list         [2,3,1,5]
  `   - repeat left as right    [2,3,1,5]
 ḣ    - head                    [2,3], [2,3,1], [2], [2,3,1,5]
   Ḍ  - from decimal lists      23, 231, 2, 2315
    S - sum                     2571

Charcoal, 10 bytes
ＩΣＩＥθ✂θ⁰Ｉι

Try it online! Link is to verbose version of code. Explanation:
   Ｅθ       Map over input string
        Ｉι  Cast current character to integer
     ✂θ⁰    Slice input string to that length
 ΣＩ         Cast slices to integer and take the sum
Ｉ           Cast result to string and implicitly print

Haha, I had the exact same thing

Octave, 56 bytes
@(n)sum(str2num(['' 32+char(n.*(find(n)<=(n'-48))-32)]))

Anonymous function that takes a string as input argument and returns a number as output.
Try it online!
The shorter version
@(n)sum(str2num(['' char(n.*(find(n)<=(n'-48)))]))

works in Matlab, because char(0) is treated as a space.

Perl 6, 27 bytes
{sum $_ X[&substr]^«.comb}

Test it
Expanded:
{  # bare block lambda with implicit param ｢$_｣

  sum

    $_           # the input

      X[&substr] # crossed using &substr sub as if it was an infix operator

    ^«\          # upto ｢^｣ for each of the following ｢«｣ (creates Range objects)
    .comb        # the input split into digits (implicit method call on ｢$_｣
}

C (gcc), 77 75 bytes
Has to be compiled with the -lm switch or GCC doesn't recognize the math functions.
r,q,i;f(n){for(r=0,i=n;i;i/=10)q=log10(n)+1-i%10,r+=n/pow(10,q>0?q:0);n=r;}

Try it online!

dc, 55 bytes
[0*]sq?dsfZ1-se[lfddZrIle^/I%-d0>qIr^/+led1-se0<a]dsaxp

No strings nor arrays! Indeed, the required digits are acquired solely through mathematical manipulation.
Try it online!

Stax, 6 bytes
ç╫&º±å

Run and debug it online
The corresponding ascii representation of the same program is this.
EZFy(e+

E        get array of digits
 Z       push 0 under array of digits
  F      for each digit, run the rest of the program
   y     input as a string
    (    get start of string for specified number of characters
     e   evaluate substring as integer
      +  add

Husk, 6 bytes
ṁd´M↑d

Try it online!
Explanation
ṁd´M↑d  -- example input: 1301
     d  -- decimal digits: [1,3,0,1]
  ´M    -- map over it using it as argument (example with 3):
    ↑   -- | take: [1,3,0]
        -- : [[1],[1,3,0],[],[1]]
ṁ       -- map and then sum the result (example on [1,3,0]):
 d      -- | as decimal: 130
        -- : 1 + 130 + 0 + 1 = 132

Japt, 5 bytes
Takes input as a string.
¬x@¯X

Try it

Explanation
          :Implicit input of integer string U
¬         :Split to an array of characters/digits
  @       :Pass each X through a function
   ¯X     :Slice U from the first to the Xth character
 x        :Reduce by addition

O_o Either Japt is really golfy or I'm doing Actually wrong

@ASCII-only: Japt is a lot more "golfy" than most people realise; we win our fair share of challenges, even beating Charcoal and SOGL in a recent [tag:ascii-art] challenge.

@Shaggy Sure, but I didn't realize it was Jelly/Actually/05AB1E level golfy

@ASCII-only: Oh, yeah, it's definitely up there with them, holding it's own nicely :) If you're interested, have a look at our language of the month nom. or drop into the Japt chatroom sometime and we'll give you a tour.

J, 18 bytes
[:+/"."0".@{."0 1]

Explanation
Takes a string as input
           {."0 1  - take
    "."0           - current char as int items
                 ] - from the argument
         ".        - and convert them to an integer
[:+/               - add them up

Try it online!

REXX 118 bytes
pull n
l=length(n)
a=0
j=1
do while (j<=l)
if substr(n,j,1)==0 then m=0;
else m=substr(n,1,substr(n,j,1));
a=a+m
j=j+1
end
say a

Try it here
Provide Input value in the STDIN tab.

Actually, 10 bytes
╝ß⌠≈╛H≈⌡MΣ

Try it online!
Explanation
╝          Push input to register 1
 ß         Push n-th input (0 by default)
        M  Map
  ⌠    ⌡   Function
   ≈       Cast current character of input to int
    ╛      Get value of register 1 (input)
     H     Push input[:current character]
      ≈    Cast to int
         Σ Sum

JavaScript, 43 bytes
It's well after 3 in the morning, why am I still golfing?!
Takes input as a string.
s=>(g=x=>s[x]?+s.slice(0,s[x])+g(++x):0)(0)

Try it online

Perl 5, 26 bytes
Includes +1 for p
perl -pE 's%.%/.{0,$&}/;$\+=$&%eg}{' <<< 2315; echo

K4, 22 bytes
Solution:
+/10/:'(x&#x)#\:x:10\:

Examples:
q)k)+/10/:'(x&#x)#\:x:10\:13214
1468
q)k)+/10/:'(x&#x)#\:x:10\:1301
132
q)k)+/10/:'(x&#x)#\:x:10\:251
278
q)k)+/10/:'(x&#x)#\:x:10\:2315
2571

Explanation:
Break into base-10, take min of each number and the length of list from this. Convert back and sum up.
+/10/:'(x&#x)#\:x:10\: / the solution
                  10\: / to base 10, 123 => 1 2 3
                x:     / save as x
             #\:       / take (#) each left
       (    )          / the left
          #x           / count (#) length of x
        x&             / min of x and the length
  10/:'                / from base 10 each
+/                     / sum up the results

Java 8, 92 bytes
n->n.chars().map(c->(c-=48)>0?new Integer(n.substring(0,c<n.length()?c:n.length())):0).sum()

Explanation:
Try it online.
n->                                  // Method with String parameter and int return-type
  n.chars()                          //  Loop over the characters
   .map(c->(c-=48)                   //   Convert character to digit
        >0?                          //    And if it's larger than 0
         new Integer(n.substring(0,  //     Take the first `x` digits, where `x` is:
          c<n.length()?              //      If the digit higher than the total a.o. digits
           c                         //       Take the first `c` digits
          :                          //      Else:
           n.length()))              //       Take all digits
         :                           //    Else:
          0)                         //     Take 0
   .sum()                            //   And sum everything

Python 3, 66 bytes
lambda n:sum([int(str(n)[:int(i)])if i!='0'else 0for i in str(n)])

Try it online!

Jelly, 6 bytes
DµḣµVS

Try it online!
Get the Digits of the input, then get the first [each digit] elements of the input (ḣead), then eVal each sum to make it a number again and Sum.