g | x | w | all
Bytes Lang Time Link
012APLNARS250318T202408ZRosario
032JavaScript Node.js250318T163924Zl4m2
033Janet250318T142145Zxigoi
091BitCycle u240305T013931ZDLosc
037Swift 5.9230723T210854ZmacOSist
030Scala 3240303T145008Zmovatica
047C clang230722T003423Zc--
028Kamilalisp230518T182027ZKamila S
039Python230515T153508ZUtility
039Python230513T125503ZThe Empt
134Pascal230513T142051ZKai Burg
003Nekomata + e230512T105051Zalephalp
002Thunno 2230502T123959ZThe Thon
002Vyxal230501T183648Zemirps
442TypeScript's Type System230501T214543ZTristan
064Lua230502T002444Zbluswimm
005APLDyalog Unicode230501T231941Zc--
012Vyxal230501T153522ZLarry Ba
066PARI/GP230416T123139Z138 Aspe
004Stax230403T235111Zemirps
008vemf230328T133418Zlyxal
039Desmos210624T161555ZAiden Ch
028Regex ECMAScript+?^=RME230324T221740ZDeadcode
nan230325T071012ZThe Thon
017TIBasic230325T003810ZYouserna
003Japt210624T084017ZShaggy
006Pyt230117T015151ZKip the
153Nibbles230116T233816ZDominic
022Arturo230116T224835Zchunes
023Factor + math.unicode210624T081747Zchunes
024GAP220218T110756ZDavid Sc
003Husk220218T001818ZDominic
007Risky210624T084409Zxigoi
011Zsh210624T064819Zpxeger
004BQN211210T142232ZRazetime
020jq211003T002001ZSara J
005RAD211002T221814ZAdalynn
064C gcc210629T040555Ztsh
00305AB1E210628T210533ZMakonede
006GolfScript210628T170039ZSoup Gir
007APLDyalog Unicode210624T195122ZAZTECCO
031Pari/GP210627T093216ZJoe Slat
016Wolfram Language Mathematica210625T205155Zatt
027R210624T074813ZdigEmAll
005Stax210625T122304ZMulti
013Zsh210625T110405ZDS-Charl
072C gcc210624T155037ZNoodle9
043Java JDK210625T055633ZOlivier
046Red210624T065442ZRazetime
006Julia 1.5210625T011029ZGlen O
033Python 3210624T225615ZHunaphu
031Python 3210624T073707Zdingledo
029Haskell 1 indexed210624T125429ZWheat Wi
014Raku210624T181644ZSean
036jq210624T091346Zcnamejj
020Wolfram Language Mathematica210624T072010Ztheorist
003Pyth210624T142606ZMr. Xcod
030JavaScript ES6210624T104349ZArnauld
038Perl 5210624T093752ZKjetil S
003Brachylog210624T092342ZUnrelate
026Retina 0.8.2210624T090455ZNeil
038JavaScript Node.js210624T071959Zemanresu
003Vyxal rR210624T070643Zemanresu
046C# Visual C# Interactive Compiler210624T071054ZLiefdeWe
021Ruby210624T080656Zuser1007
024R210624T075530ZRobin Ry
006Charcoal210624T074714ZNeil
007J210624T065041ZBubbler
003Jelly210624T062919Zhyperneu
005APL Dyalog Unicode210624T063824Zhyperneu

APL(NARS), 12 chars

{⍵≡⍦{⍵}¨⍳≢⍵}

test:

  f←{⍵≡⍦{⍵}¨⍳≢⍵}
  f 1 2 3 4
1
  f 1 2 2 3
0
  f 1 3 2 4
1
  f 1
1
  f 2
0
  f 1 2 3
1
  f 1 2 2
0
  f 
SYNTAX ERROR
  f 
  ∧

it is right: one has to write the operator ugual among sets that have repetition where 2 sets are ugual if have the same elements and each element is repeted the same number of times in both the sets.... Something as this:

r←a ug b;la;i
r←0⋄i←1⋄a←,a⋄b←,b⋄la←≢a⋄→0×⍳la≠≢b
→3×⍳i>la⋄→0×⍳(+/b=a[i])≠+/a=a[i]⋄i+←1⋄→2
r←1

and then the function for the exercise

h←{⍵ug⍳≢⍵}

but here we have operator ≡⍦ that even if

 1 3 2 ≡⍦ 1 2 3
1
 1 3 2 ≡⍦ ⍳3
0

the operator ≡⍦ help with workaround. Just I don't know if is faster h or f. I think is faster h if sets are random or (not=) 90% of time.

JavaScript (Node.js), 32 bytes

s=>s.every((_,i)=>s.includes(i))

Try it online!

JavaScript (Node.js), 38 bytes

s=>s.sort()==s.map((_,i)=>i).sort()+''

Try it online!

Janet, 33 bytes

|(deep=(sort $)(range(length $)))

Takes an array.

BitCycle -u, 91 bytes

v 0< <  <
ABv
^/=^?^
v<
Hvv <<
/<CDv
!v /=^
v  =\\\v
 ~~< >+
    <@>G^
 >E\^
>~> \/
 > F//@

Outputs 1 for truthy, 0 for falsey. Try it here!

Explanation

The algorithm is as follows:

The program contains two main sections, one that accomplishes step 1 and one that accomplishes steps 2 and 3. Here they are as separate programs:

Step 1

?0 v
v  <
ABv
^/=^
  C\!

Subtracts 1 from every number in the list. Try it!

We prefix a 0 bit to the input so every unary number has a leading 0. Each time through the A-B loop, we use the first bit to set the switch (=) and then send it into the C collector.

The upshot is that one bit from each of the unary numbers gets discarded, subtracting 1 from each of them.

Steps 2-3

?0v  <
  CDv
 v /=^
v  =\\\v
 ~~< >+
    < >G\!
 >E\^@
>~> \/
 > F//@

Halts if there are no zeros or multiple zeros in the list, otherwise filters the zero(s) out of the list. Try it!

We once again prefix a 0 bit to the input. (In the actual program, this only needs to be done once.) Each time through the C-D loop, we use the first bit to set the northeast switch (=).

The upshot is that all the bits after the first go back into C unchanged, but if the first bit was 0, the second bit sets the southwest switch and some bits go into E.

Meanwhile, the first bit goes through this structure:

 =
=\\\v
  >+
   >G

Starting from the northeast switch moving south, it bounces off the westernmost two splitters (\) and is sent to the branch (+). If it is 1, it turns right and goes into the G collector. If it is 0, it turns left, bounces off the easternmost splitter, passes back through the other two splitters, and reaches the southwestern switch.

The upshot is that G gets the same list but without any 0 bit that is followed by another 0 bit or the end of the string. Also, F gets a bit for each of the 0 bits that didn't go into G, and E is guaranteed to have at least one bit in it.

Next, the E collector opens, dumps its first bit into F, and discards the rest. F now contains one bit if there were no zeros in the list, two bits if there was exactly one zero, and more than two if there were multiple zeros.

The bits from the F collector then go through this structure:

   @
> \/
 F//@

The upshot is that if there was not exactly one zero in the list, the program halts. No bits have been output yet, which with the -u flag means the output is 0. If there was exactly one zero, the program does not halt; the G collector opens and the program continues.

Tying it together

In the full program, the output from the G collector is sent back into A, starting the loop over again.

Meanwhile, the discarded 1 bits from step 1 have been collected in H. Once there are no bits left in the main loop, H opens. The splitter (/) sends its first bit into the sink (!), outputting 1. The rest of the bits go through the splitter and off the playfield.

Swift 5.9, 50 48 42 37 bytes

let p={Set($0+[])==Set(1...$0.count)}

Play the fiddle!

Scala 3, 36 30 bytes

l=>l.toSet==(1to l.size).toSet

Attempt This Online!

C (clang), 47 bytes

Input is a null-terminated array of positive integers

i;f(*a){return!a[i++]?i=0,1:!wcschr(a,i)<f(a);}

Try it online!


C (gcc) -m32, 35 bytes

Requires that you also pass the length

f(a,n){n=!n||wcschr(a,n)*f(a,n-1);}

Try it online!

Kamilalisp, 28 bytes

[≡ $(+ 1)∘⍳∘⍴ ⊼]

Determines whether the sorted vector is equal to the range [1, length(input)].

Attempt This Online!

Kamilalisp, 24 bytes

[≡ #0 ⍋@⍋]@$(^- 1)

A port of the APL answer.

Attempt This Online!

Python, 39 Bytes

lambda x:sorted(x)==list(range(len(x)))

I am an account owned by PlaceReporter99. I am trying to get 20 rep so that I can access the chat rooms.

Python, 43 39 Bytes

lambda x:sorted(x)==list(range(len(x)))

0-indexed. Uses sorted(), range() and list(). Surprisingly gives correct answer for empty list.

Test on TIO.

Pascal, 134 Bytes

This function requires a processor supporting Extended Pascal as defined by ISO standard 10206 (level 1).

type Z=integer;function f(A:array[p..q:Z]of Z):Boolean;var S:set of Z;i:Z;begin S:=[];for i:=p to q do S:=S+[A[i]];f:=S=[1..q-p+1]end;

Ungolfed:

function f(A: array[minimum..maximum: integer] of integer): Boolean;
var
    members: set of integer value [];
    i: integer;
begin
    { transform an ordered `array` into an unordered `set` }
    for i := minimum to maximum do
    begin
        { form the union of two sets }
        members := members + [A[i]]
    end;
    { analyze: compare `members` to a set of `[1..n]` }
    f := members = [1..(maximum - minimum + 1)]
end;

Evidently, the implementation is index-insensitive.

Nekomata + -e, 3 bytes

x↕=

Attempt This Online!

Inputs are 0-indexed.

x↕=
 ↕    Find a permutation of
x     the range from 0 to the length of the input minus 1
  =   that is equal to the input

The -e flag prints True if there is a solution, and False otherwise.

Thunno 2, 2 bytes

ėṗ

Output with inverted booleans (allowed by community consensus). Add the ! flag if you want 1 for truthy and 0 for falsy.

Explanation

ė   # Length range
 ṗ  # Set difference

Screenshot

Screenshot

Vyxal, 2 bytes

ż⊍

Try it Online!

Uses inverted truthiness (non-empty array for falsy, empty array for truthy)

This follows Vyxal's truthiness conventions, which can be checked using a boolify: Verify all test cases online! (boolified and logical NOT applied).

ż  # length range
 ⊍ # setwise difference

TypeScript's Type System, 450 442 bytes

type A<T extends any[]>=T extends{length:infer L}?(L extends number?L:never):never
type B<L extends number,T extends 0[]=[]>=T extends{length:L}?T:B<L,[...T,0]>
type C<N extends number,T extends number=1,R extends any[] = []> = R['length']extends N?R:C<N,A<[...B<T>,0]>,[...R,T]>
type D<T extends any[],U extends any[]>=T extends[]?true:T extends[infer H,...infer R]?H extends U[number]?D<R,U>:false:never
type F<T extends any[]>=D<T,C<A<T>>>

TypeScript Playground Link

Explanation

// This allows getting the Length of any tuple via inferring its L property
type A<T extends any[]>=T extends{length:infer L}?(L extends number?L:never):never

// This creates a tuple of arbitrary length L (we need to use this later for arithmetic)
type B<L extends number,T extends 0[]=[]>=T extends{length:L}?T:B<L,[...T,0]>

// We can use this to generate an incrementing tuple of length L (e.g. [1, 2, 3, 4]). We use this to compare against the final array.
type C<N extends number,T extends number=1,R extends any[] = []> = R['length']extends N?R:C<N,A<[...B<T>,0]>,[...R,T]>

// This checks if two arrays have the same elements inside them 
type D<T extends unknown[],U extends unknown[]>=T extends[]?true:T extends[infer H,...infer R]?H extends U[number]?D<R,U>:false:never

// Finally, we can use this to compare the chosen array T vs the increasing tuple N
type F<T extends any[]>=D<T,C<A<T>>>

Lua, 64 bytes

load't=...table.sort(t)for i=1,#t do b=b or i~=t[i]end return b'

Try it online!

Truthy and falsy values are swapped.

APL(Dyalog Unicode), 5 bytes SBCS

^/⍋∊⊢

Try it on APLgolf!

A tacit function that returns if every number from 1..n is in the array.

Explanation

^/⍋∊⊢
^/    all
  ⍋   (a permutation of) numbers from 1..n
   ∊  are members of
    ⊢ the array

Vyxal, 12 bytes

?£(|)1¥G›r¥⁼

Try it Online!

PARI/GP, 66 bytes

Try it online!

f(a)={for(i=1,#a,if(setsearch(Set(a),i)==0,return(0)));return(1);}

Stax, 4 bytes

àæ↓Δ

Run and debug it

This is Packed Stax which unpacks to the following 5 bytes:

%Rx-!

Run and debug it

 R    # range 1..
%     # input length
  x-  # setwise difference with register x (which is set to the input by default)
    ! # logical NOT

vemf, 8 bytes

{α~↨≡│α≤

enter image description here

Explained

{α~↨≡│α≤
{        # Monadic function that checks if
      α≤ # the sorted input
    ≡    # equals
 α~↨     # range(1, len(input) + 1)

Desmos, 54 39 bytes

f(l)=0^{(l.sort-[1...l.total])^2.total}

Test on function f. Returns 1 if truthy, 0 if falsey.

To be honest, I thought that the solution would be shorter than this :|. Could most likely be golfed though, with a different strategy than mines.

Ok well I got much better at golfing in Desmos since 2021 and all I can say is that there are some pretty glaring byte saves in my previous version.

Try It On Desmos!

Try It On Desmos! - Prettified

Regex (ECMAScript+(?^=)RME), 37 30 28 bytes

(:x*)x\b(.*\1x:|(?^!.*\1\b))

Takes its input in unary, as a concatenation of strings of x characters whose lengths represent the numbers, separated and enclosed on both sides by : characters. Example: :xxx:x:xx: represents 3,1,2.

Try it on replit.com - ECMAScript+(?^=) (RegexMathEngine -xli)

Asserts that there exists no element \$n\$ for which there either is a subsequent duplicate element \$n\$, or for which there doesn't exist any element \$n-1\$ anywhere in the list if \$n\ne 1\$.

Returns "match" for falsy and "no match" for truthy (inverted logic).

              # No anchor - can match starting at any point in the string
(:x*)x\b      # Start at any list element; \1 = {that element} - 1, including
              # the bounding character on its left side, consuming it without
              # consuming the bounding character following it.
(
    .*\1x:    # Match any subsequent list element whose value equals \1 + 1
|         # or...
    (?^!      # Negative lookinto - assert that the following pattern cannot
              # match the entire input string:
        .*    # Skip to any list element, putting it in tail (Works in concert
              # with the following expression's matching of the left-side
              # bounding character contained in \1)
        \1\b  # Assert that tail==\1, or if \1==0 this can match at the edge
              # of any element in the list (if we didn't need \1==0 to be able
              # to match, we could have used "\1:" instead)
    )
)

Using comma delimiting (e.g. xxx,x,xx) instead of this input method, would take +5 bytes:

\b(x*)x\b(.*,\1x\b|(?^!.*\b\1\b))

Regex (PCRE+(?^=)RME), 29 bytes

^:(x*:(?^=.*:((?(2)\2)x):))*$

Try it on replit.com - PCRE+(?^=) (RegexMathEngine --pcre -xli)

Golfwise, this is obsoleted by the 28 byte version above, but is kept here due to still being close in length, and using a different algorithm.

Iterate once for each list element: Find a list element whose value is the index of the current loop iteration. (Uses a nested backreference to accomplish this.)

Returns "match" for truthy and "no match" for falsy.

^                     # Anchor to start
:                     # Consume initial bounding character
(                     # Loop the following:
    x*:               # Consume one list element
    (?^=              # Lookinto - is matched against the entire string
        .*:           # Skip to any list element, putting it in tail
        (             # \2 = the  following:
            (?(2)\2)  # If \2 is set (i.e., if we're not on the first iteration)
                      # then include the previous value of \2 in its new value
            x         # Append one more "x" (if this is the first iteration,
                      # captures just one)
        )
        :             # Consume one bounding character
    )
)*                    # Iterate the above as many times as possible, minimum 0
$                     # Assert we've reached the end of the string

Using comma delimiting (e.g. xxx,x,xx) instead of this input method, would take +2 bytes:

^(x+,?(?^=.*\b((?(2)\2)x)\b))*$

But that regex is incredibly slow, and it takes another +1 byte to give it reasonable speed:

^(x++,?(?^=.*\b((?(2)\2)x)\b))*$

Regex (ECMAScript 2018 / Pythonregex / .NET), 38 31 29 bytes

(:x*)x\b.*(\1x:|$(?<!\1\b.*))

Try it online! - ECMAScript 2018
Try it online! / Attempt This Online! - Python (with regex)
Try it online! - .NET

A port of the 37 30 28 byte version, using variable-length right-to-left evaluated lookbehind instead of lookinto. Like it, returns "match" for falsy and "no match" for truthy (inverted logic).

               # No anchor - can match starting at any point in the string
(:x*)x\b       # Start at any list element; \1 = {that element} - 1, including
               # the bounding character on its left side, consuming it without
               # consuming the bounding character following it.
.*             # Skip to any subsequent position in the string
(
    \1x:       # Match any subsequent list element whose value equals \1 + 1
|          # or...
    $          # Assert that we're at the end of the string
    (?<!       # Negative lookbehind - using right-to-left evaluation starting
               # from the current position (so read this from bottom to top),
               # assert that the following cannot match:
        \1\b   # Assert that head==\1, or if \1==0 this can match at the edge
               # of any element in the list (if we didn't need \1==0 to be able
               # to match, we could have used "\1:" instead)
        .*     # Skip to anywhere in the string, putting it in head
    )
)

Using comma delimiting (e.g. xxx,x,xx) instead of this input method, would take +5 bytes:

\b(x*)x\b.*(,\1x\b|$(?<!\b\1\b.*))

Try it online! - ECMAScript 2018

Regex (.NET), 36 35 bytes

^:(x*:(?=.*(?<=:(x(?(2)\2)):.*)))*$

Try it online!

Golfwise, this is obsoleted by the 29 byte version directly above, but is kept here due to still being close in length, and using a different algorithm.

A port of the 29 byte PCRE+(?^=)RME version, using variable-length right-to-left evaluated lookbehind instead of lookinto. Like it, returns "match" for truthy and "no match" for falsy.

^                     # Anchor to start
:                     # Consume initial bounding character
(                     # Loop the following:
    x*:               # Consume one list element
    (?=               # Lookahead
        .*            # Skip to later in the string (".*$" would be faster)
        (?<=          # Lookbehind - evaluated right-to-left (so read this
                      # from bottom to top)
            :             # Consume one bounding character
            # Assert head==1 (on the first iteration) or head==\2+1 (on
            # subsequent iterations), capturing this as the new value of \2
            (
                x         # Append one more "x" (if this is the first iteration,
                          # captures just one)
                (?(2)\2)  # If \2 is set (i.e., if we're not on the first
                          # iteration) then include the previous value of
                          # \2 in its new value
            )
            :.*           # Skip to any list element, putting it in head
        )
    )
)*                    # Iterate the above as many times as possible, minimum 0
$                     # Assert we've reached the end of the string

Using comma delimiting (e.g. xxx,x,xx) instead of this input method, would take +2 bytes:

^(x+,?(?=.*(?<=\b(x(?(2)\2))\b.*)))*$

But that regex is incredibly slow, and it takes another +2 bytes to give it reasonable speed:

^(x+\b,?(?=.*(?<=\b(x(?(2)\2))\b.*)))*$

Try it online!

Regex (ECMAScript 2018 / Java / Pythonregex / .NET), 44 37 35 bytes

(:x*)x\b(.*\1x:|(?<!(?=.*\1\b)^.*))

Try it online! - ECMAScript 2018
Try it online! - Java
Try it online! / Attempt This Online! - Python (with regex)
Try it online! - .NET

Based on the 37 30 28 byte version (inverted logic).

Java needs to be "hinted" as to how far the lookbehind should go, thus necessitating the use of a lookahead inside the lookbehind.

Regex (ECMAScript+(?*)RME / PCRE2 v10.35+), 41 39 bytes

^(?*.*(:x*)x:)((.*\1x\b){2}|(?!.*\1\b))

Try it on replit.com - ECMAScript+(?*) (RegexMathEngine -xml)
Attempt This Online! - PCRE2 v10.40+

A port of the 38 31 29 byte version, using molecular lookahead instead of variable-length right-to-left evaluated lookbehind. Like it, returns "match" for falsy and "no match" for truthy (inverted logic).

^                # Anchor to start
(?*              # Molecular (non-atomic) lookahead - try all possible matches
    .*(:x*)x:    # Skip to any list element; \1 = {the element} - 1, including
                 # the bounding character on its left side
)
(
    (
        .*\1x\b  # Match and consume any subsequent list element whose value
                 # equals \1 + 1, without consuming the bounding character on
                 # its right side (to allow this group to be repeated)
    ){2}         # Iterate the above 2 times
|          # or...
    (?!          # Negative lookahead - assert that the following cannot match:
        .*       # Skip to any list element, putting it in tail (Works in
                 # concert with the following expression's matching of the
                 # left-side bounding character contained in \1)
        \1\b     # Assert that tail==\1, or if \1==0 this can match at the edge
                 # of any element in the list (if we didn't need \1==0 to be
                 # able to match, we could have used "\1:" instead)
    )
)

Regex (ECMAScript+(?*)RME / PCRE2 v10.35+), 44 42 bytes

^(?!.*(:x*)\b.*\1:|(?*.*(:x+)x:)(?!.*\2:))

Try it on replit.com - ECMAScript+(?*) (RegexMathEngine -xml)
Attempt This Online! - PCRE2 v10.40+

Asserts that there exists no element \$n\$ for which there is a subsequent duplicate element \$n\$, and that there exists no element \$n≥2\$ for which there is no element \$n-1\$ anywhere in the list.

Returns "match" for truthy and "no match" for falsy.

This non-inverted logic version is being kept up, despite losing in golf to the inverted logic 41 39 byte version above, to show how close it comes in length. This is because the second half of the logic, that asserts there are no non-consecutive elements, cannot be golfed by inverted logic, since the .*: must be inside the molecular lookahead.

^                  # Anchor to start
(?!                # Negative lookahead - assert that the following cannot match:
    .*(:x*)\b      # Skip to any list element; \1 = the element, including the
                   # bounding character on its left side
    .*             # Skip to any list element, putting it in tail (Works in
                   # concert with the following expression's matching of the
                   # left-side bounding character contained in \1)
    \1:            # Assert tail == \1
|              # or...
    (?*            # Molecular (non-atomic) lookahead - try all possible matches
        .*(:x+)x:  # Skip to any list element that's ≥ 2; \2 = {the element} - 1,
                   # including the bounding character on its left side
    )
    (?!            # Negative lookahead - only matches outside if the pattern
                   # inside fails to match.
        .*         # Skip to any list element, putting it in tail (Works in
                   # concert with the following expression's matching of the
                   # left-side bounding character contained in \2)
        \2:        # Assert tail == \2
    )
)

Thunno -, \$ 8 \log_{256}(96)\approx \$ 6.58 bytes

Iz:DLRA=

Attempt This Online!

Input as each number on its own line.

Explanation

Iz:DLRA= # Implicit input. - flag subtracts one.
Iz:      # All inputs, sorted
   DLR   # Duplicate and push the length range
      A= # Are equal?
         # Implicit output 

TI-Basic, 17 bytes

Prompt A
SortA(ʟA
min(ʟA=cumSum(1 or ʟA

Japt, 4 3 bytes

0-based

Íe¶

Try it or run all test cases

Saved a byte thanks to Etheryte pointing out one of my own favourite tricks that I somehow forgot!

Íe¶     :Implicit input of array
Í       :Sort
 e      :Every?
  ¶     :  Equal to its 0-based index

Pyt, 6 bytes

şĐŁř=Π

Try it online!

ş              implicit input; sort in ascending order
 Đ             duplicate
  Ł            get length
   ř           push [1,2,... length]
    =          element-wise equal with sorted array?
     Π         product of booleans; implicit print

returns 1 if permutation of [1,2,...]; 0 otherwise

Nibbles, 1.5 bytes (3 nibbles)

-,,

Returns an empty list (falsy) if input is a permutation of 1..n, or a non-empty list (truthy) if it is not.

-       # remove 
 ,      #   sequence of 1..
  ,     #   length of
        #   (implicitly) input
        # from
        #   (implicitly) input

enter image description here

Arturo, 22 bytes

$[a][=sort a 1..max a]

Try it

Checks whether the input sorted is equal to \$[1..\mathrm{max}(input)]\$.

Factor + math.unicode, 24 23 bytes

[ dup length iota ⊃ ]

Try it online!

0-indexed to save a byte. Is the input a superset of \$[0..|input|)\$?

GAP, 24 bytes

p:=l->PermList(l)<>fail;

Try it online!

This is a little trick since PermList fails if l is not a permutation of 1...length(l). However, due to technical reasons this is actually a boolean value. From the GAP documentation:

fail is simply an object that is different from every other object than itself.

For technical reasons, fail is a boolean value. But note that fail cannot be used to form boolean expressions with and, or, and not

The operator <> tests for inequality.

Husk, 3 bytes

-ŀ¹

Try it online!

What's left after removing (-) 1..length_of_input (ŀ¹) from the input?
Empty list = falsy (so input is permutation of 1..n); Non-empty list = truthy (input is not permutation of 1..n).

Risky, 7 bytes 7 bytes and a palindrome

1_??!0:0!??_1

Try it online!

Explanation

1   sort
_
?         input
?     filter by
!       factorial
0         0
: =
0   range
!       length
?         input
?     find first number such that
_
1         1

Zsh, 18 12 11 bytes

>$@<{1..$#}

Attempt This Online!

Outputs via exit code: 0 for a permutation and 1 for not a permutation

Explanation:

If any command fails, then that means one of the files in the range didn't exist, so it's not a valid permutation, and zsh will exit with status 1.

BQN, 4 bytesSBCS

∧≡⊒˜

Run online!

Uses this tip.

jq, 20 bytes

[range(max)+1]==sort

Try it online!

Explanation

       max            # Get the maximum of the input
 range(   )           # Generate the non-negative integers below that
           +1         # Add 1 to each of them
[            ]        # Collect as list
                sort  # Sort the input list
              ==      # Compare the two lists

RAD, 5 bytes

<≡⍳∘⍴

Try it online!

 ≡       - Check equality between ...
<        - ... the input vector ...
  ⍳∘     - ... and 1 through ...
   ⍴     - ... the length of the input vector.
   

C (gcc), 64 bytes

f(a,n,i)int*a;{for(i=n;i--&&a[i]-n;);n=~i?f(a,n,a[i]=a[--n]):n;}

Try it online!

05AB1E, 3 bytes

{āQ

Try it online!

{āQ  # full program
  Q  # is...
 ā   # implicit input...
{    # sorted...
  Q  # equal to...
 ā   # [1, 2, 3, ..., length of...
     # implicit input...
{    # sorted...
 ā   # ]...
  Q  # ?
     # implicit output

GolfScript, 6 bytes

~.,,-!
~      # parse the input string as an array
 .,,   # create an array [0 1 2...] of the same length as the input
    -  # get the set difference of this array and the original
     ! # convert the empty/non-empty array into a 1 or 0

Try It Online!

APL(Dyalog Unicode), 117 bytes SBCS

∧/⍳∘⍴∊⊢

Try it on APLgolf!

Old explanation

∧/     all
(⍳⍴⍵)  [1..length]
∊⍵     belongs to input?

Pari/GP, 31 bytes

f(v)=vecsort(v)==vector(#v,i,i)

Try it online!

Wolfram Language (Mathematica), 16 bytes

PermutationListQ

Try it online!

R, 27 bytes

any(rank(x<-scan(),,'f')-x)

Try it online!

Returns FALSE for Truthy, TRUE for FALSY (just to shave one byte)

Explanation:

If the array containing the rank of each value is equal to the input array, then it's a permutation of 1..n

Note:
5 bytes are wasted because in rank function the default handling strategy in case of ties is "average their ranks" instead of any of the other possibilities... argh!

Stax, 5 bytes

c%R|}

Run and debug it

Explanation:

     ; Implicit input onto top of stack
c    ; Copy top of stack
%    ; Length of top of stack
R    ; Make range [1 .. n]
|}   ; Compare top two elements of stack. Arrays are different orderings of same elements?
     ; Implicit output of truthy/falsy

Could probably save a byte somewhere.

Zsh, 13 bytes

: >$@<{1..$#}

Try it online!

:              noop command to prevent hanging while waiting for input
  >$@          create a file for every argument
     <{1..$#}  read every file between 1 and the number of arguments

Since the redirects are handled left-to-right, we create the files before trying to read them. If we encounter a number for which no file exists (for example on zsh x.zsh 4 1 2), we get the following error:

no such file or directory: 3

and receive exit code 1. If it was indeed a permutation, we exit cleanly with code 0.

C (gcc), 95 73 72 bytes

r,t,i,j;f(a,n)int*a;{for(r=i=n;i--;r*=!t)for(t=j=n;j--;)t*=i!=a[j];n=r;}

Try it online!

Inputs a pointer to an array \$a\$ of zero-based integers and its length \$n\$ (since C pointers to arrays carry no length information).
Returns a truthy value if all \$0\dots (n-1)\$ integers are present or a falsey value otherwise.

Explanation

Goes through all the numbers \$0\dots (n-1)\$ (in reverse order) and tests to see if they're in \$a\$.

Saved a whopping 19 bytes thanks to AZTECCO!!!

Java (JDK), 43 bytes

a->a.sorted().reduce(1,(x,y)->y==x?x+1:0)>0

Try it online!

Explanations

This answer is a Predicate<IntStream> and requires that the input contains no 0.

First this code sorts the input stream. The reduce method then makes sure that each consecutive number is encountered, and return the last encountered number. x always contains the next expected number, or 0 if we got an unexpected number. 1 is the first parameter of the reduce method as it's the first expected number. Given that 0, or any negative number, is not allowed in the IntStream, when 0 is returned for the first time, it will always be returned for the remaining of the process.

Red, 46 bytes

func[a][i: 0 until[alter a i: 1 + i]single? a]

Try it online!

increments a counter as long as the counter is found in the list, and then checks it against the length.

1 = length? is used as a polyfill for single? in the latest Red version.

-5 bytes from tsh.

-5 bytes from Galen Ivanov.

Julia 1.5, 6 bytes

This is a built-in, so it's quite easy for Julia

isperm

Use it like this: isperm([6,3,8,12,1,10,4,2,7,9,5,11])

Python 3, 33 bytes

lambda x:max(*x,len(x))^len({*x})
  1. Check uniqueness: len(x) = len(set(x))
  2. For unique set: max(x) == len(x) iff x = 1...n

Try it online!

Python 3, 31 bytes

Input is \$ 0 \$-indexed.

lambda a:{*a}=={*range(len(a))}

Try it online!

This is the most obvious implementation I could think of. It compares the set of \$ a \$ to the set of numbers from 0 to len(a)-1.

Python 3, 30 bytes

As @ovs suggested, we can save a byte by switching the definition of truthy and falsey. A valid permutation returns a falsey value, and truthy otherwise.

lambda a:{*a}^{*range(len(a))}

Try it online!

Haskell (1 indexed), 29 bytes

Courtesy of AZTECCO

g l=all(`elem`l)[1..length l]

Try it online!

Haskell (0 indexed), 42 32 31 bytes

Lynn saved one byte with the pointfree solution.

all.(.fst).flip elem<*>zip[0..]

Try it online!

I tried a bunch of creative stuff with scans, folds and zips, but the boring solution ended up being the shortest.

Both of these check that every integer in the available range is in the list. The first is 1 to the length of the list, the second is 0 to 1 less than the length of the list.

Raku, 14 bytes

{$_∖bag ^$_}

0-based.

Try it online!

jq, 20 49 36 bytes

length==max and max==(unique|length)

Try it online!

Thanks to tsh and xigoi for catching mistakes in the previous attempts...

Third time is the charm perhaps?

Since the rules limit the numbers to "positive integers", there's no need to test the minimum. Making sure the largest number in the list, the size of the original list and the size of a de-dup'd list are all the same is sufficient. So that's what this version does.

Wolfram Language (Mathematica), 22 20 bytes

Sort@#==Range@Max@#&

-2 bytes, thanks to @ZaMoC:

Try it online!

Pyth, 3 bytes

UIS

Try it online!

JavaScript (ES6), 30 bytes

Expects 0-indexed values. Returns a Boolean value.

a=>a.every(x=>(a[~x]^=1)/a[x])

Try it online!

Commented

We test whether all values are less than the length \$N\$ of the input array and make sure that there is no duplicate. Both conditions are satisfied iff the array consists of all values from \$0\$ to \$N-1\$.

a =>             // a[] = input array
  a.every(x =>   // For each value x in a[]:
    (a[~x] ^= 1) //   ~x is -x - 1, which is guaranteed to be negative
                 //   Therefore, a[~x] is a property (such as '-1') of
                 //   the underlying object of a[], which can be safely
                 //   used to store values that were already encountered
                 //   If a[~x] XOR 1 is not equal to 1, we have a
                 //   duplicate value
    / a[x]       //   We also make sure that a[x] is defined, which
                 //   means that x < a.length
                 //   The possible cases are:
                 //     1 / n, n > 0 is a truthy number  \__ success
                 //     1 / 0 is +Infinity (also truthy) /
                 //     1 / undefined is NaN (falsy)     \
                 //     0 / n, n > 0 is 0 (falsy)         |_ failed
                 //     0 / 0 is NaN (falsy)              |
                 //     0 / undefined is NaN (falsy)     /
  )              // End of every()

Perl 5, 38 bytes

sub{!grep!{map+($_,1),@_}->{$_},1..@_}

Try it online!

Brachylog, 3 bytes

o~⟦

Try it online!

0-indexed. Succeeds or fails.

o      The input sorted
 ~⟦    is the range from 0 to something inclusive.

Note that this can not be golfed to ⟦p with reversed input, as it fails to terminate for cases it should reject:

⟦     Choose an integer. Is the range from 0 to it inclusive
 p    a permutation of the input?

Retina 0.8.2, 26 bytes

\d+
$*_
O`
^
¶
(^¶_|\1_)+$

Try it online! Takes input on separate lines but link is to test suite that splits on commas for convenience. 1-indexed. Explanation:

\d+
$*_

Convert to unary, but using a non-digit character.

O`

Sort.

^
¶

Prefix a newline, so that each number is now preceded by a newline.

(^¶_|\1_)+$

If at the beginning of the buffer, match a newline followed by 1 (in unary), otherwise match one more than the previous match (still with preceding newlines). If the input was a permutation then the buffer will contain an ascending sequence and the match will reach the end of the buffer.

JavaScript (Node.js), 40 38 bytes

s=>s.sort((a,b)=>a-b).some((x,i)=>x^i)

Try it online!

Returns true for invalid and false for valid. Put a ! before the s.sort for the otherway round. Takes input 0-indexed.

Vyxal rR, 5 3 bytes

GṖc

Try it Online!

-2 thanks to lyxal

C# (Visual C# Interactive Compiler), 46 bytes

a=>{a.Sort();int i=1;return a.All(x=>x==i++);}

Try it online!

Ruby, 21 bytes

->a{a|[*1..a.max]==a}

Try it online!

-1 byte thanks to ovs!

-3 bytes thanks to Razetime!

R, 26 24 bytes

-2 bytes thanks to pajonk.

all(seq(x<-scan())%in%x)

Try it online!

If input is of length at least 2, seq(x) outputs the integers from 1 to length(x); if input is of length 1, it outputs the integers from 1 to x. Return TRUE iff all those integers are elements of x.

Charcoal, 6 bytes

¬⁻Eθκθ

Try it online! Link is to verbose version of code. 0-indexed. Outputs a Charcoal boolean, i.e. - for permutation, nothing if not. Explanation:

   θ    Input array
  E     Map over elements
    κ   Current index
 ⁻      Remove values found in
     θ  Input array
¬       Check that nothing is left
        Implicitly print

(Mapping over the input indices is golfier than creating a range.)

J, 7 bytes

-:/:@/:

Try it online!

Ninja'd by hyper-neutrino :(

Takes zero-based input. Applying Grade Up twice to a vector gives a "ranking" of each element, so that 0 is the smallest, 1 is the next smallest, ... up to n-1, breaking ties by giving a smaller number to the one appearing first. A vector is a permutation if and only if the ranking is identical to itself.

J, 7 bytes

2|C.!.2

Try it online!

Takes zero-based input. C.!.2 is a built-in for "cycle parity". It gives 1 if a permutation has even number of swaps, -1 if odd, and 0 if not a valid permutation. I take it modulo 2 to convert all nonzero results to 1 (the only truthy value in J).

Even if error/non-error output were allowed, it is too bad that permutation-related built-ins A. and C. don't error on all possible non-permutations.

J, 7 bytes

#\-:/:~

Try it online!

Takes one-based input. #\ is a golfing trick for getting 1..n, which is compared to the sorted array /:~ of the original.


If output by erroring/non-erroring is allowed:

J, 3 bytes

C.~

Try it online!

Takes zero-based input. Abuses dyadic form of C., whose left argument must strictly be a permutation. It throws an index error otherwise.

Jelly, 3 bytes

Ṣ⁼J

Try it online!

Ṣ⁼J   Monadic Link
Ṣ     1-chain: sort the input
 ⁼J   2,1-chain: is (the input sorted) equal to (range on the length of the input)?

APL (Dyalog Unicode), 5 bytes

⊢≡⍋∘⍋

Try it online!

-4 bytes thanks to Bubbler by turning this into a train and via using ⍵≡ to match the whole array instead of ∧/⍵= to match element-wise and then reduce by AND.

⊢≡⍋∘⍋    Train
 ≡         Check equality between
⊢         (Right argument ⍵) and
  ⍋∘⍋    Composed function {⍋⍋⍵}; grade up twice

Grading up twice gives the minimum permutation of length X that has the same (non-strict) ordering as the original - so, if the permutation of the right order is the same as the original, then the original was that permutation and thus a permutation.