11
\$\begingroup\$

Given a matrix of non-negative numbers (of arbitrary dimension) and a number, get all multi-dimensional indices of the number in that list.

For example, let's say we have the list [[0,1,0],[1,0,0]] and the number 1. In the first list, we see one 1 at the second index. If we were using one-based indices, this would be index [1,2]. In the second list, there is another 1 at the first index, so this would be index [2,1]. The final list would be [[1,2], [2,1]].

Rules

  • Standard loopholes apply
  • Matrix will:
    • only use non-negative numbers
    • not be ragged
    • never be empty
    • every inner list will always have the same length at its depth
    • always be at least 2-D, and never 1-D or 0-D
  • You may take input/output in any reasonable format
  • You can use one-based or zero-based indexes
  • Built-ins are allowed, but I encourage giving non-builtin answers if you do use them
  • This is , so shortest code wins

Test cases (zero-based indexes)

[[0, 1, 0], [1, 0, 0], [1, 1, 1]], 1 => [[0, 1], [1, 0], [2, 0], [2, 1], [2, 2]]
[[[2, 3, 4], [3, 1, 5]], [[0, 2, 3], [3, 2, 3]]], 3 => [[0, 0, 1], [0, 1, 0], [1, 0, 2], [1, 1, 0], [1, 1, 2]]
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Can I take the number of dimensions as input? \$\endgroup\$
    – mousetail
    Jul 3 at 19:45
  • \$\begingroup\$ @mousetail Yes, sounds reasonable enough \$\endgroup\$
    – Steffan
    Jul 3 at 19:45
  • 2
    \$\begingroup\$ Mathematica's builtin Position does exactly this, even if the list is arbitrarily ragged. \$\endgroup\$ Jul 4 at 20:05

12 Answers 12

7
\$\begingroup\$

K (ngn/k), 2 bytes

where equal? Returns a matrix with a column for each index.

&=

Try it online!


A non-builtin solution, 32 bytes:

{$[x~*x;!'&x~y;,/(!#x),''x o'y]}

Try it online!

This is recursive function taking the array as first argument x and the element as second argument y.

$[ ; ; ] is the ternary operator.
x~*x If the first value of the array matches the array (this is only the case if x is a number) ...
    x~y does the single number match the searched value? (booleans are 0 and 1)
    & A list with that many 0s.
    !' Convert each zero to an empty range. This results in the empty list if x and y are different, and in a list containing an empty list otherwise. Returns a list of indices.

Otherwise, if x is an array with at least one axis ...
    x o'y Call the function recursively on each subarray in x.
    !#x Range from 0 to length of x - 1.
    ,'' Prepend the index of the subarray to each index in the recursive results.
    ,/ Flatten into a single list of indices.

\$\endgroup\$
4
\$\begingroup\$

Python, 91 85 83 bytes

-6 bytes thanks to @Steffan

-2 bytes thanks to @movatica

f=lambda a,b,c:c and[(i,*j)for i,d in enumerate(a)for j in f(d,b,c-1)]or[[]]*(a==b)

Attempt This Online!

\$\endgroup\$
2
3
\$\begingroup\$

Python NumPy, 33 bytes

lambda a,b:zip(*(a==b).nonzero())

Attempt This Online!

Admittedly a bit trivial.

Test harness borrowed from @mousetail.

\$\endgroup\$
2
\$\begingroup\$

JavaScript, 60 bytes

n=>g=(m,...p)=>m.flatMap?.((v,i)=>g(v,...p,i))??(m-n?[]:[p])

f=

n=>g=(m,...p)=>m.flatMap?.((v,i)=>g(v,...p,i))??(m-n?[]:[p])

console.log(JSON.stringify(f(1)([[0, 1, 0], [1, 0, 0], [1, 1, 1]]))) // [[0, 1], [1, 0], [2, 0], [2, 1], [2, 2]]
console.log(JSON.stringify(f(3)([[[2, 3, 4], [3, 1, 5]], [[0, 2, 3], [3, 2, 3]]]))) // [[0, 0, 1], [0, 1, 0], [1, 0, 2], [1, 1, 0], [1, 1, 2]]

\$\endgroup\$
1
  • 1
    \$\begingroup\$ ?. … ?? could be a very common pattern for nested arrays. \$\endgroup\$
    – tsh
    Jul 4 at 2:23
2
\$\begingroup\$

Python 2, 70 bytes

f=lambda l,t,a=[]:l>[]and f(l.pop(),t,a+[len(l)])+f(l,t,a)or[a]*(t==l)

Try it online!

This takes advantage of Python 2's comparison treating lists as greater than integers. This lets us use a single check l>[] which is false for integers as well as the empty list, which both are directed to the base case. Here, if the input is an integer that matches the target value, we return a singleton list of the list of indices a that we've built up if, and otherwise the empty list.

The recursive call either goes deeper into the last element which is popped, appending the length of the resulting list as the newest index, or continuing with the now-shorter list.

\$\endgroup\$
2
\$\begingroup\$

JavaScript (V8), 60 bytes

Expects (n)(array). Prints the 0-based multi-dimensional indices.

n=>g=(a,...b)=>a.map?a.map((v,i)=>g(v,...b,i)):a-n||print(b)

Try it online!

Or 57 bytes by using optional chaining, as suggested by @tsh:

n=>g=(a,...b)=>a.map?.((v,i)=>g(v,...b,i))||a-n||print(b)

(not supported by either TIO or ATO)

\$\endgroup\$
1
  • 1
    \$\begingroup\$ 57: n=>g=(a,...b)=>a.map?.((v,i)=>g(v,...b,i))||a-n||print(b) \$\endgroup\$
    – tsh
    Jul 4 at 2:29
1
\$\begingroup\$

JavaScript (Node.js), 65 64 bytes

z=>f=x=>x.at?x.flatMap((y,i)=>f(y).map(w=>[i,...w])):x-z?[]:[[]]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Retina, 58 bytes

Lv$`(\b\d+\b).*\b\1$
$`
+`\[[^][]+]
0
%|',L$`\[(\d+,)*
$#1

Try it online! Link includes test cases. Explanation:

Lv$`(\b\d+\b).*\b\1$
$`

Extract the prefixes of the input at every instance of the given number.

+`\[[^][]+]
0

Simplify irrelevant elements from lists into numbers.

%|',L$`\[(\d+,)*
$#1

Calculate the multidimensional index corresponding to each found element.

\$\endgroup\$
1
\$\begingroup\$

05AB1E, 29 24 bytes

QI<Ý"€"×€"Dÿƶ˜0Ks"J.V\)ø

1-based output.

-5 bytes (replacing DΔ€`}\N with I<) by taking the dimensions as additional third input

Try it online or verify all test cases.

Explanation (of original answer):

Q                # Given the (implicit) multi-dimensional input-list and (implicit)
                 # input-integer, check which are equal
 DΔ€`}\N         # Determine the depth-1 of this multi-dimensional list:
 D               #  Duplicate the multi-dimensional list of 0s/1s
  Δ              #  Loop until the result no longer changes:
   €`            #   Flatten it one level down
     }\          #  After the loop: discard the resulting flattened list
       N         #  And push the last (0-based) index of the loop instead
Ý                # Pop and push a list in the range [0,depth-1]
 "€"×            # Map each to that many "€" as string
     €           # Then map each string to:
      "Dÿƶ˜0Ks"  #  String "Dÿƶ˜0Ks", where `ÿ` is replaced with the "€"-string
               J # Join this list of strings together
.V               # Evaluate and execute it as 05AB1E code:
       D         #  Duplicate the multi-dimensional list of 0s/1s
        €        #  Zero or more `€`: map to a certain depth:
         ƶ       #   Multiply each value by its 1-based index
          ˜      #  Flatten the multi-dimensional list
           0K    #  Remove all 0s
             s   #  Swap, so the multi-dimensional list of 0s/1s is at the top again
  \              # Discard the last multi-dimensional list of 01s/1s
   )             # Wrap all flattened lists on the stack into a list
    ø            # Zip/transpose; swapping rows/columns
                 # (after which the result is output implicitly)

Minor note: "€"× cannot be '€×, because this is the dictionary word for "view": try it online.

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 200 196 bytes

-4 bytes thanks to @ceilingcat

f(a,x,n)char*a,*x;{for(int i[n],d=-1,c;*a;){*a==91?i[++d]=0:*a-93?*a-44?:++i[d]:--d;for(c=0;*a>47&*a<58;)c+=c<0|*a++-x[c]?~c:1;a+=!c;if(c==strlen(x)){for(c=0;c<n;)printf("%d ",i[c++]);puts("");}}}

Try it online!

\$\endgroup\$
0
1
\$\begingroup\$

R, 19 bytes

\(m,x)which(m==x,T)

Attempt This Online!

R has almost exactly the correct built-in for this.


R, 64 59 bytes

Edit: -5 bytes thanks to pajonk

\(m,x,k=t(t(expand.grid(lapply(dim(m),`:`,1)))))k[m[k]==x,]

Attempt This Online!

Roll-your-own solution without using which.

expand.grid is used to generate all possible sets of indices, which are then tested to see whether the element is equal to the searched-for x. Unfortunately, expand.grid outputs a "data.frame" (an R-specific matrix-like data type, but that isn't a matrix): pajonk's golf is to transpose twice (t(t(...))) to convert into a matrix, saving 5 bytes compared to the more-conventional as.matrix(...)...

\$\endgroup\$
3
  • \$\begingroup\$ -8 bytes \$\endgroup\$
    – pajonk
    Jul 6 at 20:12
  • \$\begingroup\$ @pajonk - That's very neat! Thanks! Is there already a tip for that...? \$\endgroup\$ Jul 6 at 20:20
  • 1
    \$\begingroup\$ Apparenly yes, but I know it from golfs under my own answers ;) Also, you didn't notice edit in my comment :-) BTW, "data.frame" i R is actually more of a "list-like" object than "matrix-like" (it's actually a list of columns). \$\endgroup\$
    – pajonk
    Jul 6 at 20:29
0
\$\begingroup\$

Ruby, 59 bytes

->a,n{r=0;a.map{|b|r+=1;c=0;b.map{|d|c+=1;d==n&&p([r,c])}}}

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.