Is it zero- or one- indexed?

Your task is to determine whether some arbitrary programming language has zero-indexed or one-indexed arrays based on sample inputs and outputs

Inputs

• An array of integers with at least 2 elements
• A positive integer index
• The value of the array at that index

Output

One of four distinct values representing:

• One-indexed if the language unambiguously has one-indexed arrays
• Zero-indexed if the language unambiguously has zero-indexed arrays
• Unknown if the given inputs aren't enough to determine whether the language is zero- or one- indexed because it is ambiguous.
• Neither if the language is not zero- or one-indexed because it is something else that may or may not make any sense.

Example Test Cases

Formatted as [array, elements][index] == value_at_index => output

[2, 3][1] == 2  ==>  one-indexed
[2, 3][1] == 3  ==>  zero-indexed
[1, 2, 2, 3][2] == 2  ==>  unknown
[4, 5][1] == 17  ==>  neither
[-3, 5, 2][2] == 5  ==>  one-indexed
[-744, 1337, 420, -69][3] == -69  ==>  zero-indexed
[-744, 1337, 420, -69][3] == 420  ==>  one-indexed
[-744, 1337, 420, -69][3] == -744  ==>  neither
[42, 42, 42, 42, 42][2] == 42  ==>  unknown
[42, 42, 42, 42, 42][1] == 56  ==>  neither


Rules and Scoring

• Use any convenient I/O methods
• Use any convenient representation for each of the four distinct categories as long as it is consistent and each possible category is mapped to exactly one value.
• You may assume that all array values are between $$\-2^{31}\$$ and $$\2^{31} - 1\$$, inclusive (i.e. the signed int32 range.)
• You may assume that arrays are no longer than $$\65535\$$ elements.
• You may assume that the index is in-bounds for both zero- and one-indexed semantics.

Shortest code wins. Happy golfing!

• Can we get a guarantee that the given index exists in the list, regardless of whether it is 0 or 1 indexed? Feb 26 at 17:47
• @DonThousand Yes: "You may assume that the index is in-bounds for both zero- and one-indexed semantics." Feb 26 at 17:52
• Here are the test cases in a more machine-friendly format of (array, index, element, output as list of 0 and/or 1).
– xnor
Feb 26 at 17:54
• What about [7, 7, 2, 7][2] == 7? On one hand looks like it could be 1-indexed, buuuut it could also be "-1"-indexed (which is weird, but still). Feb 28 at 12:45
• @Vilx- [3, 7, 2, 7][2] == 7 would be a better example, because yours could be 2-indexed, too. But I think the question only considers 0, 1, either and neither as possibilities. Feb 28 at 13:43

convey, 47 bytes

Returns 0 for neither, 1 for one-based, 2 for zero-based and 3 for unknown.

{2+~0
?;\2:!2[
v^<]
?;\?+2
v^< v*+}
!>>>=?^
2


Try it online!

Run for 1 2 2 3 with index 2 and value 2:

On the left we split the input lines with ;\ ^< into the three paths. The first one pushes two zeroes after length of path + index time steps into the +. The second one path tries to push the array into + – if there are values waiting (the two zeroes), they get passed through unaltered. Otherwise, they get deleted ?]. The two values then get pushed into =, where they are compared to the third input. The result are two boolean bits. The second one gets multiplied by 2, then they get added together.

Brainfuck, 43 bytes

,>,[->,<],<[->->-<<]>[[-]>>++<<]>[[-]>+<]>.

Arguments are taken in this order: value_at_index, index, array values.

Outputs are: 0-unknown, 1-zero indexed, 2-one indexed, 3-neither.

How it works

,               read value_at_index into first cell
>,              read index into second cell
[->,<]          read the array till the one indexed element is found and store it into third cell
,               store the zero indexed element into second cell
<[->->-<<]      substract value_at_index from both saved elements
>[[-]>>++<<]    if the zero indexed element isn't equal to zero then add 2 to result
>[[-]>+<]       if the one indexed element isn't equal to zero then add 1 to result
>.              print the result

• Welcome to Code Golf! Nice first answer. Feb 27 at 19:41

(l%i)n=[l!!j==n|j<-[i,i-1]]


Try it online!

Outputs a two-element list like True/False.

28 bytes

(l%i)n=[l!!i==n,l!!(i-1)==n]


Try it online!

28 bytes

(l%i)n=(==n).(l!!)<$>[i,i-1]  Try it online! 29 bytes n?i=map(==n).take 2.drop(i-1)  Try it online! JavaScript (ES6), 30 bytes Returns 0 for neither, 1 for 0-indexed, 2 for 1-indexed or 3 for unknown. (a,i,v)=>a[i]==v|2*(a[i-1]==v)  Try it online! or 28 bytes by outputting a pair of Boolean values: (a,i,v)=>[a[i]==v,a[i-1]==v]  Try it online! • Wow, was just about to submit a 44 byte solution. Great job! – user100690 Feb 26 at 17:48 Jelly, 5 bytes +.ịẹ⁵  Try it online! or see the test cases (slightly modified to run as a function) Full program, takes input as index, array, value on the command line. Outputs [1] for one-indexed, [2] for zero-indexes [1, 2] for unknown and [] for neither How it works +.ịẹ⁵ - Main link. Takes index on left and array on right . - Yield 0.5 + - Add to index ị - Yield [array[index], array[index+1]] ẹ⁵ - Return the indices of the value in that array  Pyth, 11 bytes xE,@QJE@QtJ  Test suite Takes input in the form: list value index  Translation of caird coinheringaahing's Jelly answer. R, 26 bytes function(a,i,n)a[0:1+i]==n  Try it online! Inputs array a, index i, value n. Outputs a boolean pair: F T = 0, T F = 1, T T = unknown, F F = either. Full program for the same byte count, inputs in the order of i n a merged into a single vector: R, 26 bytes a=scan();a[2:3+a[1]]==a[2]  Try it online! APL (Dyalog Unicode), 15 13 bytes Saved 2 bytes thanks to Kamil Drakari {⍵=⍺⍺[⍺,⍺+1]}  Try it online! Call it with index (array f) value). Returns 0 1 if it's zero-indexed, 1 0 if it's one-indexed, 1 1 if it's unknown, and 0 0 if it's neither. {⍵=⍺⍺[⍺,⍺+1]} [ ] ⍝ Index into ⍺⍺ ⍝ the array (the left operand) ⍺ ⍝ at the given index (the left argument) (one-indexed) , ⍝ and (parentheses would have been better, but , saves a byte) ⍺+1 ⍝ index+1 (zero-indexed) ⍵= ⍝ Compare the value (right argument) to this 2-element vector  • I know J but not much APL. What is happening with the (array f) part? Feb 26 at 18:57 • @Jonah f is the dop in my submission - I had to make an operator so it could take three arguments. array f gives back a function taking the index on the left and the value on the right. The parentheses are really just there to show APL that the left operand is just array and not the array index array. – user Feb 26 at 19:08 • Ah, ok, so to translate to J terminology your submission is an adverb which modifies an array, returning a verb which then takes two args. Nice way to fake a 3 arg function! Feb 26 at 20:09 • Can you remove the 2⊥ and just output as a two item array? That seems to be a common output format among other answers, and making the change on tio seems to still give correct results, but there could be something I'm not aware of that makes it a problem. Feb 27 at 18:01 • @KamilDrakari You're right, I just edited my answer to do that. I guess I was using 2⊥ because returning an array felt too cheaty – user Feb 27 at 23:48 MATL, 5 bytes tQh)=  Inputs are: index, array, value. Outputs are 1 0 for one-indexed, 0 1 for zero-indexed, 1 1 for unknown, 0 0 for neither. (Also for 5 bytes: FT+)=). Explanation t % Implicit input: index. Duplicate Q % Add 1 h % Concatenate ) % Implicit input: array. Apply index = % Implicit input: value. Test for equality. Implicit display  Perl 5 -apl, 40 bytes $_=1*($F[$i=<>]!=($t=<>)).($F[$i-1]==$t)


Try it online!

Input is on three lines:

Space separated list of numbers
index
target value

Output Meaning
0 Zero-indexed
11 One-indexed
01 Unknown
1 Neither

Japt, 8 bytes

gVôJ)®¥W


Outputs [true, false] for one-indexed, [false, true] for zero-indexed, [true, true] for unknown, and [false, false] for neither. Takes inputs in the order array, index, value.

Explanation:

gVôJ)®¥W
Vô         # Create an array starting at input 2...
J)       # ...And ending -1 integers later
g           # Get the values from input 1 at those indices (0-indexed)
®      # Replace each value with:
¥W    #  Is it equal to input 3?


C (gcc), 42 40 bytes

Saved 2 bytes thanks to att!!!

f(l,i,e)int*l;{e=l[i]==e|2*(l[i-1]==e);}


Try it online!

Inputs a pointer to the array, the index, and the test element.
Returns $$\2\$$ for $$\1\$$-indexed, $$\1\$$ for $$\0\$$-indexed, $$\3\$$ for unknown, and $$\0\$$ for neither.

• f(l,i,e)int*l;{e=l[i--]==e|2*(l[i]==e);} for 40
– att
Feb 26 at 21:14
• @att Nice one - thanks! :D Feb 26 at 21:23
• @att and Noodle9: you can do it without unsequenced i-- by using [i] and [i-1], in that order, instead of [i--] and [i]. Same result, same size, but avoids undefined behaviour. (Why are these constructs using pre and post-increment undefined behavior?). I know this answer happens to work with gcc -O0, but it's always nice when we can write "better" code without making it larger. Feb 28 at 4:22
• @PeterCordes I totally get where you're coming from. I code professionally in C++ for low-latency and am constantly worried about things like sequence points. In code-golfing most of this gets gleefully tossed into the bin. Code happily updated - thanks! :D Feb 28 at 9:05
• Oh for sure, if there was anything to be saved by UB that happens to work, I'd recommend just commenting on the UB. (Ugh, just noticed that this is omitting return, so there's no C reason for this to work at all, only a coincidence of gcc -O0 code-gen. (unlike i-- / i where it's more understandable why it happens to work.) But this fall-off-the-end silliness is standard for code-golf unfortunately, so I guess doesn't need to be mentioned in every answer.) Feb 28 at 9:34

x86 (with MMX) machine code, 9 bytes

(Same machine code works in 64-bit and 32-bit modes; 16-bit mode doesn't have scaled-index addressing modes.)

2 boolean compare results from array[index-1] == element and array[index] == element can be concatenated to produce a 2-bit return value: one or the other set means we can tell that it's 0 (first) or 1 (second) indexed. Neither set means "neither", both set means "unknown". Apparently we don't consider it ambiguous if the expected element is also present somewhere else in the array; "neither" is only a fallback that we don't have to consider if 0-indexed or 1-indexed explains the observation.

So we only need to look at 2 elements at index-1 and index, e.g. with a packed-compare of those 2 elements in parallel. That's exactly what MMX pcmpeqd mm1, mm2/m64 does.

Array pointer in EDI/RDI, index in EDI/RSI, expected element in mm0 (in the low 32-bit element), retval in mm0

  line  offset   machine            NASM source
#             code
1                         compare_at_index:
2 00000000 0F62C0             punpckldq   mm0, mm0                 ; broadcast expected
3 00000003 0F7644B7FC         pcmpeqd     mm0, [rdi + rsi*4 - 4]   ; compare integers at array[i-1, i]
4 00000008 C3                 ret
size = 9 bytes


Return values, as a SIMD vector of 2 32-bit dword elements [low, high] (shown in memory order, not Intel's usual notation of highest element first):

• [-1, 0] means 0-indexed, only the first matched
• [0, -1] means 1-indexed
• [-1, -1] means "unknown"; both matched
• [0, 0] means "neither"; neither matched

(Untested but I'm confident this works, and writing a test harness would be significantly more work for asm. SIMD packed compares are a pretty normal thing to work with.)

If you wanted to compact that return value into a scalar integer bitmap, that costs 3 bytes for pmovmskb eax, mm0 (0F D7 C0) which would give you a 0x0F / 0xF0 / 0xFF / 0x00 result in EAX.

(If this was an XMM register, we could use movmskps to get 1 bit from each 4-byte element, instead of 4. Or movmskpd to get 2 bits total from a 16-byte vector. But SSE2 instructions on XMM registers are 1 byte longer than MMX, so even using 64-bit array elements wouldn't let us keep the code-size the same. Also, SSE2 would require a 16-byte memory operand to be aligned unless you use a separate movups load instruction, although AVX allows vpcmpeqq xmm0, xmm0, [rdi+rsi*8-8] with no alignment requirement.)

Most standard calling conventions expect you to use emms after using MMX registers, but I'm considering a hypothetical system where it's normal to pass around integers in MMX registers, never returning the FPU to x87 mode.

If you wanted the expected-element to arrive in an integer register, say EDX, you could use 0F 6E C2 movd mm0, edx before punpckldq. Unfortunately, vpbroadcastd xmm0, edx requires AVX512 with its longer EVEX encoding, and only works for 16-byte XMM registers not 8-byte MMX. If we took the element as a stack arg, pshufw mm0, [rsp+8], 0b0100_0100 is 6 bytes total, same as movd+punpckldq. 2 register args with the rest on the stack is a pretty normal calling convention, especially for 32-bit mode (e.g. __fastcall, but that would want ret 4 callee pops. So maybe gcc -m32 -mregparm=2 with [esp+4]). Not that we need to justify our calling convention as being a standard one.

Java, 44 bytes

a->i->v->a[i]==v?a[i-1]==v?1:2:a[i-1]==v?3:4


Returns:

• 1, if unknown
• 2, if zero-indexed
• 3, if one-indexed
• 4, if neither

Try it online!

• This was my solution in JavaScript, except the arrows were =>
– user100690
Feb 26 at 18:16
• 38 bytes with 3=unknown, 2=1-indexed, 1=0-indexed, 0=neither. Feb 27 at 9:43
• Even with the current approach you can save two bytes by testing a[i-1] first.
– Neil
Mar 2 at 10:33

PowerShell, 38 36 35 bytes

Takes three arguments: the array to index into, the index to test, and the number to test for. Outputs 0 or 1 for 0 or 1 based indexing, respectively, outputs 0 and 1 for unknown, and outputs nothing for neither.

param($a,$b,$c)0,1|?{$a[$b--]-eq$c}


Try it online!

PowerShell, 33 bytes

This version has completely unintuitive output, but still works. Outputs 1 for 0-based, 0 for 1-based, 0 and 1 for neither, and nothing for unknown

param($a,$b,$c)0,1|?{$c-$a[$b--]}


Try it online!

Charcoal, 9 bytes

Ｅ²⁼ζ§θ⁻ηι


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

Neither  0-indexed   1-indexed   Unknown
-                       -
-           -


Explanation:

 ²          Literal 2
Ｅ           Map over implicit range (i.e. 0, 1)
η    Second input
⁻     Subtract
ι   Current value
§       Indexed into
θ      First input
⁼         Equals
ζ        Third input
Implicitly print


J, 13 bytes

1 :'=u{~],<:'


Try it online!

Thanks to user's APL answer for suggesting the idea of using a J adverb to emulate a 3-argument function

The solution is an adverb f that operates like this:

<expected value> (<array> f) <index>


Return value key:

1 0 = zero-indexed
0 1 = one-indexed
1 1 = can't tell
0 0 = neither

• = Does the expected value equal...
• ],<: The index, catted with "index - 1"
• u{~ Both taken from the given array? (In J, within an adverb definition, u is the canonical name given to "the noun or verb being modified")

Python 2, 32 bytes

lambda l,i,n:[l[i]==n,l[i-1]==n]


Try it online!

Outputs a two-element list of Booleans for whether 0-indexing and 1-indexing are consistent with the input.

• So, the interpretation legend is {(False, True): "One-indexed", (True, False): "Zero-indexed", (True, True): "Unknown", (False, False): "Neither"} ? Feb 26 at 22:21
• @JamesTheAwesomeDude Yes exactly
– xnor
Feb 27 at 2:16

Wolfram Language (Mathematica), 25 24 bytes

Sign[#2[[#;;#+1]]-#3]^2&


Try it online!

Input [index, array, value]. Returns {0,1} for 1-indexed, {1,0} for 0-indexed, {0,0} for both, and {1,1} for neither.

jq, 22 bytes

Inputs as: [index, array, value].

Output key: true,false for 1-indexed, false,true for 0-indexed, true,true for unknown, false,false for 0-indexed.

.[1][.[0]|.-1,.]==.[2]


Explanation

.[1]                    # Index the array by the indices:
[.[0]               #    * The index
|.-1,.]        #    * Prepended with the index - 1
==      # Vectorizing equality:
.[2]  # With the value


Rust, 31 bytes

|a:&[_],i,v|(a[i]==v,a[i-1]==v)


Try it online!

Port of Arnauld's JavaScript answer. Returns

(false, false) => "neither"
(false, true) => "one-indexed"
(true, false) => "zero-indexed"
(true, true) => "unknown"


I had to include the :&[_] part for the code to compile, but I have the feeling that it can be optimized somehow.

Julia, 18 bytes

l*i*r=l[i:i+1].==r


Try it online!

overloads the * operator, expecting array*index*result

Outputs [1,0] for one-indexed, [0,1] for zero-indexed, [0,0] for neither and [1,1] for unknown

GolfScript, 11 bytes

~].~==\~(==


Try it online!

Ruby, 30 bytes

->(a,i,v){[a[i]==v,a[i-1]==v]}


returns:

• [true, false], if zero-indexed
• [false, true], if one-indexed
• [true, true], if unknown
• [false, false], if neither

Try it online!