23
\$\begingroup\$

The \$\text{argwhere}\$ function takes a list of values and a predicate/boolean function as arguments and returns a list of indices where the predicate function returns true in the input list. For example,

argwhere([1, 2, 3, -5, 5], x -> x > 2)

would produce an output of [2, 4] because those are the (0-indexed) indices whose values are greater than two.

Challenge

Implement the \$\text{argwhere}\$ function in your language of choice.

Format

For the purposes of this challenge, we will deal with lists of integers. You must accept a list of integers and a black box function and return a list of integers in any reasonable format. You may assume the input list will never be empty. Your output may be either 0-indexed or 1-indexed — please specify which.

Rules

  • Builtins are allowed, but please consider adding a less trivial answer so we can see how \$\text{argwhere}\$ might be implemented in your language.
  • Explaining your answer(s) is encouraged!
  • Standard loopholes are forbidden.
  • This is , so the code with the fewest bytes (in each language) wins.

Why argwhere?

argfoo is a naming convention where you don't want the elements themselves — you want their indices or some other quality. \$\text{argmax}\$, \$\text{argmin}\$, and \$\text{argsort}\$ are examples of this. Read more about it here. (Also, because my favorite programming language comes with this function and it's called arg-where. 🤫)

Test cases

0-indexed

Input Output
[1, 2, 0, 0, 3, 0, 0, 0, 4], x -> x == 0
[4, 3, 5, 7, 11, 13, 17], x -> x % 2 == 0
[8, 9, 10, 11, 12, 13], x -> x + 10 > 20
[5, -5, 2, -2, 0], x -> x < 0
[5, 2, 0], x -> x < 0
[2, 3, 5, 6, 7]
[0]
[3, 4, 5]
[1, 3]
[]

1-indexed

Input Output
[1, 2, 0, 0, 3, 0, 0, 0, 4], x -> x == 0
[4, 3, 5, 7, 11, 13, 17], x -> x % 2 == 0
[8, 9, 10, 11, 12, 13], x -> x + 10 > 20
[5, -5, 2, -2, 0], x -> x < 0
[5, 2, 0], x -> x < 0
[3, 4, 6, 7, 8]
[1]
[4, 5, 6]
[2, 4]
[]
\$\endgroup\$
10
  • \$\begingroup\$ I don't know how to do black-box functions in Charcoal but normally I would use FindAll(Map(<array>, <expression>), 1). \$\endgroup\$
    – Neil
    Commented Jan 19, 2022 at 9:58
  • 3
    \$\begingroup\$ husk,1 byte: W \$\endgroup\$
    – Razetime
    Commented Jan 19, 2022 at 10:17
  • \$\begingroup\$ Just out of curiosity, is there any language that actually has a function called "argwhere"? \$\endgroup\$
    – ophact
    Commented Jan 19, 2022 at 10:18
  • \$\begingroup\$ @ThisFieldIsRequired Yep! See docs.factorcode.org/content/… \$\endgroup\$
    – chunes
    Commented Jan 19, 2022 at 10:24
  • \$\begingroup\$ Are we allowed to output the indices in reversed order? \$\endgroup\$ Commented Jan 19, 2022 at 10:49

40 Answers 40

11
\$\begingroup\$

Python 3.8 (pre-release), 45 bytes

lambda l,F:[i for i,e in enumerate(l)if F(e)]

Try it online!

Looks like it won't get much shorter than this.

Explanation: keep all indexes (found by unpacking; the index is the first item of each 2-element tuple in the return value of enumerate) for which the function returns True for the corresponding element.

\$\endgroup\$
6
  • \$\begingroup\$ best python solution \$\endgroup\$
    – DialFrost
    Commented Jan 19, 2022 at 10:18
  • 1
    \$\begingroup\$ @DialFrost Is it the best one possible, though? \$\endgroup\$
    – ophact
    Commented Jan 19, 2022 at 10:19
  • \$\begingroup\$ maybe im trying it out right now \$\endgroup\$
    – DialFrost
    Commented Jan 19, 2022 at 10:25
  • 1
    \$\begingroup\$ @jwodder I would have preferred to use 3.9, however on TIO the latest version is listed as "3.8 (pre-release)", and it's a lot more convenient to use TIO, so I decided to just use that. \$\endgroup\$
    – ophact
    Commented Jan 20, 2022 at 2:08
  • 1
    \$\begingroup\$ BTW, if you want to run a newer version of Python online, Attempt This Online is currently on Python 3.10.0. \$\endgroup\$
    – DLosc
    Commented Jan 20, 2022 at 3:03
9
\$\begingroup\$

Haskell, 28 bytes

p!v=[i|(i,x)<-zip[0..]v,p x]

Try it online!

Explanation

To get the indices we zip the list with the natural numbers [0..]. Then we use a list comprehension to get only the correct indices.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ import Data.List;findIndices happens to be the same length :) \$\endgroup\$
    – lynn
    Commented Jan 20, 2022 at 14:23
7
\$\begingroup\$

Raku, 13 bytes

{grep :k,|@_}

Try it online!

Raku's grep filtering built-in can return matching indices instead of matching values if given the adverb :k. This is just an anonymous function that adds :k to the arguments it's given and passes them all to grep.

Raku's function objects actually have an assuming method that returns a new function with some of the arguments to the original function fixed in advance, so this code would more idiomatically be written &grep.assuming(:k) or the even terser &grep.assuming:k, but that's too long for golf.

\$\endgroup\$
6
\$\begingroup\$

R, 24 bytes

function(x,f)which(f(x))

Try it online!

Uses R's built-in which function, which is pretty-close to argwhere except for the manner in which x and f are supplied...


R, 26 bytes

function(x,f)seq(!x)[f(x)]

Try it online!

Roll-your-own version without any built-in.

Note that many/most R functions vectorize, and this is assumed here (and indeed applies to all the test-cases). However, this isn't universal, so if f is a non-vectorizing function we'd need +7 bytes: function(x,f)seq(!x)[sapply(x,f)].

\$\endgroup\$
1
  • 1
    \$\begingroup\$ A shame Position returns only the first match \$\endgroup\$
    – Giuseppe
    Commented Jan 19, 2022 at 22:56
5
\$\begingroup\$

Vyxal, 2 bytes

MT

Try it Online!

100% pure ascii. 0-indexed

Explained

MT
M  # Map the function to the list
 T # and return indicies where the result is truthy
\$\endgroup\$
5
\$\begingroup\$

JavaScript (V8), 34 bytes

a=>f=>a.map((x,i)=>f(x)&&print(i))

Try it online!

\$\endgroup\$
5
\$\begingroup\$

APL (Dyalog Unicode), 4 bytes

Full program. Prompts for array, then function.

⍸⎕¨⎕

Try it online!

 where

 the function

¨ mapped to

 the array

\$\endgroup\$
5
\$\begingroup\$

Java 8, 74 73 bytes

f->a->{for(int i=0;i<a.length;i++)if(f.test(a[i]))System.out.println(i);}

-1 byte thanks to @Unmitigated

0-based. Outputs the indices on separated newlines to STDOUT.

Try it online.

Explanation:

f->a->{              // Method with Function & integer-array parameters and no return
  for(int i=0;i<a.length;i++)
                     //  Loop `i` in the range [0,length):
    if(f.test(a[i])) //   If the Function for the `i`'th integer of the array is truthy:
      System.out.println(i);}
                     //    Print index `i` with trailing newline
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Using Predicate<Integer> instead of Function<Integer, Boolean> saves a byte on test rather than apply. \$\endgroup\$ Commented Oct 9, 2022 at 0:35
4
\$\begingroup\$

Pari/GP, 20 bytes

-9 bytes thanks to @Joe Slater. Didn't know that select can take a flag.

(a,g)->select(g,a,1)

Try it online!


Pari/GP, 29 bytes

(a,g)->[i|i<-[1..#a],g(a[i])]

Try it online!

\$\endgroup\$
1
  • 2
    \$\begingroup\$ This is the abbreviated form of Pari/GP’s select() statement in conjunction with apply(). The long form allows a flag to return only the indices; this answer has a nice trick to accomplish the same thing in the short form. \$\endgroup\$
    – Joe Slater
    Commented Jan 19, 2022 at 23:37
3
\$\begingroup\$

Ruby, 35 bytes

->a,f{(0..a.size).select{f[a[_1]]}}

Attempt This Online!

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

Haskell + hgl, 19 bytes

(cx<ixm pM).^m<m gu

Explanation

Here's the same code converted to a more convenient format:

f q x =
  cx $ ixM pM $ m (gu q) x

To start we have gu which takes a boolean and produces [] if false and [()] if true.

We map gu q across the input list, this converts things that pass the test to [()] and things that fail to [].

pM takes a list and a value and replaces everything in that list with that value. ixM is an index map. It combines every element with its index using some function. Here we use pM as the function so that our [()]s get replaced with [index].

Then cx concats everything back together.

You can reorganize things a bit to get:

19 bytes

cx.^ixm<(pM^.)<m gu

Which is equivalent to

f q x =
  cx $ ixM (\x y -> pM x $ gu $ q y)

But this is also 19 bytes so nothing is saved.

There is also:

19 bytes

(st.^^fl<fm cr)^.eu

This solution uses an entirely different set of tools to solve the problem but is the same length.

This can be translated to the more conventional

f q x =
  m st $ fl (q < cr) $ eu x

First eu pairs every element with its index in the list. Then fl (q < cr) filters using q on the second element of each pair. Finally m st gets all the indices from the remaining list.

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

Husk, 5 4 bytes

Edit: -1 byte thanks to Razetime

`fNm

Try it online!

Razetime already pointed-out in the comments that Husk has a one-byte built-in for argwhere: the where or W function.

So this is an implementation without W or any other function that acts-on or returns indices.

`f     # filter (select the elements that satisfy a condition)
  N    # the natural numbers
       # using this list to represent yes/no:
   m   # map 
       # the black-box function provided as (implicit) argument 1
       # across all elements of (implicit) argument 2
\$\endgroup\$
3
  • 1
    \$\begingroup\$ ηfm₁ should work. I'd argue that you can omit the explicit function argument by putting it in a separate line and calling ₁λ>20+10) with input [8,9,10,11,12,13], but husk really isn't suited for function storage anyway. \$\endgroup\$
    – Razetime
    Commented Jan 19, 2022 at 11:36
  • 1
    \$\begingroup\$ @Razetime - Yes, ηfm₁ works, but I was worried that using any function that acts-on and/or returns a list of indices is blurring the distinction to a built-in... \$\endgroup\$ Commented Jan 19, 2022 at 11:41
  • \$\begingroup\$ @Razetime - And thanks a lot for the clever implicit function argument suggestion. I agree that this is Ok, and it's much more elegant. \$\endgroup\$ Commented Jan 19, 2022 at 11:49
3
\$\begingroup\$

Wolfram Language (Mathematica), 18 bytes

Position[1>0]@*Map

Try it online!

Input [f, list]. Returns a list of 1-indexed {index}s.

Finds the positions of Trues when the function is mapped onto the list.


Wolfram Language (Mathematica), 13 bytes

Position@_?#&

Try it online!

Input [f][list]. Returns a list of 1-indexed {index}s.

Finds the positions of elements that satisfy a predicate - basically a built-in. However, this can possibly include the index of the head of the expression ({0}) if the predicate returns True when applied to that head (List).

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

Nim, 60 bytes

proc a[S,F](s:S,f:F):S=
 for i,x in s:
  if f x:result.add i

Try it online!

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

tinylisp, 84 bytes

(d w(q((L F N)(i L(i(F(h L))(c N(w(t L)F(a 1 N)))(w(t L)F(a N 1)))L
(q((L F)(w L F 0

The second line is an anonymous function that implements argwhere; the first line is a helper function. Uses 0-indexing (though it could just as easily be 1-indexing; simply change the number on the second line). Try it online!

Explanation

The helper function w, in addition to L (the list) and F (the function), gets an extra argument N (the current index). Its logic boils down to:

  • If L is nonempty:
    • If the result of calling F on the head of L is truthy, cons N to the front of a recursive call to w with arguments:
      • tail of L
      • F
      • add 1 to N
    • Else, just do the recursive call
  • Else, return L (empty list)

The anonymous function calls w with an initial index of 0.

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

JavaScript (Node.js), 34 bytes

x=>y=>x.flatMap((b,i)=>y(b)?i:[]);

Try it online!

f = x => y => x.flatMap((b, i) => y(b) ? i : []);

console.log(f([1, 2, 0, 0, 3, 0, 0, 0, 4])(x => x == 0))
console.log(f([4, 3, 5, 7, 11, 13, 17])(x => x % 2 == 0))
console.log(f([8, 9, 10, 11, 12, 13])(x => x + 10 > 20))
console.log(f([5, -5, 2, -2, 0])(x => x < 0))
console.log(f([5, 2, 0])(x => x < 0))

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

Julia 1.0, 16 bytes

l/f=findall(f,l)

Try it online!

Boring builtin, just change of order of parameters, let's move on. (The answers are all 1-indexed, by the way.)

Julia 1.0, 18 bytes

l/f=findall(f.(l))

Try it online!

This looks very similar, but works differently and shows off Julia's generalized broadcasting feature: f.(l) automatically maps f over each element of l, collects the results into an Array, type-infers that to be as a BitVector (a 1-D array of booleans), and passes that on to findall. This single argument version of findall accepts only arrays of booleans, and returns indices where there are true values.

Julia 1.0, 21 bytes

l/f=axes(l)[1][f.(l)]

Try it online!

Even avoiding findall altogether, the answer isn't too much longer!

axes(l) returns the indices in each dimension of l. Here since l is one dimensional, we take axes(l)[1] which gives the indices of the list. On that, we use Logical indexing: As seen above, f.(l) returns an array of booleans. When we use that to index within the list of indices, we get back the indices where the function f returns true.

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

Pip -xp, 7 bytes

bMa@*:1

Takes a list and a function that returns 0 (falsey) or 1 (truthy) as command-line arguments. Uses 0-indexing. Attempt This Online!

Explanation

b        ; Second argument (the function)
 M       ; Mapped to each element of
  a      ; First argument (the list)
   @*:   ; Find all indices of
      1  ; 1 (truthy)
\$\endgroup\$
3
\$\begingroup\$

J, 6 bytes

I.@:"+

Attempt This Online!

Modifier trains are such cursed constructs.

Given the explicit definition 1 :'I.u"+y' here, note that it suffices to create a verb using u and then call it with y. The possible verb trains are [:I.u"+ and I.@:(u"+).

Looking through the table of modifier trains here, V0 V1 ?? does not exist, so the former is not an option. (I guess you can get around with the conjunction versions of ] or [, but it's already anti-golfy.)

Then I looked for V0 C1 ??. V0 C1 A2 exists and we get a 3-train I.@:("+). Can we do better?

V0 C1 C2 also exists, and I.@:" means a derived conjunction I. @: (u"v). We can attach + to the right side to get the desired adverb. That is (I.@:")+. Is it OK to remove the parens here? Apparently yes, since modifier trains are evaluated in triples from the left, as opposed to regular trains that group from the right.

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

JavaScript (Node.js), 43 bytes

x=>y=>x.reduce((a,b,i)=>y(b)?[...a,i]:a,[])

Try it online!

0-indexed, takes input in curry format f(array)(function)

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Welcome to the website! \$\endgroup\$
    – ophact
    Commented Jan 19, 2022 at 10:12
  • \$\begingroup\$ @thisFieldIsRequired Thanks. \$\endgroup\$
    – Cool guy
    Commented Jan 19, 2022 at 10:16
2
\$\begingroup\$

05AB1E, 6 bytes

δ.Vƶ0K

The input black-box function is a string. 1-based.

Try it online or verify all test cases.

Explanation:

δ       # Map over the (implicit) second input-list,
        # using the first (implicit) input-string as argument:
 .V     #  Evaluate the string as 05AB1E code
   ƶ    # Multiply each item by its 1-based index
    0K  # Remove all 0s
        # (after which the result is output implicitly)
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I think you need a leading δ because you can't assume the function vectorizes correctly \$\endgroup\$
    – ovs
    Commented Jan 19, 2022 at 10:23
  • \$\begingroup\$ @ovs You're indeed correct, fixed. \$\endgroup\$ Commented Jan 19, 2022 at 10:26
2
\$\begingroup\$

Python 3, 45 bytes

def f(L,F,t=0):F(L[t])and print(t);f(L,F,t+1)

Try it online!

A function that prints the indices to STDOUT and terminates with an error.

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

Desmos, 34 bytes

a=[1...l.length]b(l)
f(l)=a[a<1/0]

\$b(l)\$ is the inputted black box function, which you will need to change for each test case (Desmos doesn't support inputting functions as arguments). \$f(l)\$ is the argwhere function. The output will be 1-indexed.

Further details in the graph links.

Try It On Desmos!

Try It On Desmos! - Prettified

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

C (gcc), 85 bytes

1-based.

Takes an integer array with a length and a function taking an integer.

m;f(s,l,p)int*s,p();{putchar(91);for(m=l;l--;s++)p(*s)&&printf("%d,",m-l);puts("]");}

Try it online!

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

tinylisp, 48 bytes

(load library
(d A(q((L F)(all-indices(map F L)1

Try it online!

The library unsurprisingly contains some rather useful functions for golfing; not sure if this should be scored as tinylisp + library. Takes the test harness from DLosc's answer.

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

Ruby, 31 bytes

->a,f{a.zip(0..){f[_1]&&p(_2)}}

Attempt This Online!

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

K (ngn/k), 12 10 9 6 bytes

{&x'y}

Try it online!

Down 3 bytes thanks to Steffan

Takes x as black box function and y as list of integers.

Explanation:

{&x'y}  Main function.
  x'y   Apply each value y to x (x(y)), return a binary list
 &      Get all the truthy indices
\$\endgroup\$
5
  • \$\begingroup\$ You can remove both @s. \$\endgroup\$
    – naffetS
    Commented Oct 8, 2022 at 2:31
  • \$\begingroup\$ This doesn't seem to produce correct output though. \$\endgroup\$
    – naffetS
    Commented Oct 8, 2022 at 2:42
  • \$\begingroup\$ I get 6 bytes: {&x'y} that produces correct output. \$\endgroup\$
    – naffetS
    Commented Oct 8, 2022 at 2:44
  • \$\begingroup\$ @Steffan Oh you are right. I read the challenge wrong, and thought that I need to return the values, not the indices. \$\endgroup\$
    – oeuf
    Commented Oct 8, 2022 at 4:18
  • \$\begingroup\$ you should probably do x'y instead of x y since the function isn't guaranteed to vectorize. like i said though, &x'y does exactly this task \$\endgroup\$
    – naffetS
    Commented Oct 8, 2022 at 15:08
2
\$\begingroup\$

Japt, 2 bytes

Black box function is pre-assigned to variable V.

ðV

Try it

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

Fig, \$2\log_{256}(96)\approx\$ 1.646 bytes

TM

Try it online!

The '>+10x20 bit in the link is the function \$f(x) = x + 10 > 20\$.

TM # Takes a function and a list in any order
 M # Map the list by the function
T  # Return the truthy indexes of the resulting list
\$\endgroup\$
2
\$\begingroup\$

J, 13 11 bytes

2 bytes saved thanks to Razetime's approach of using I.

1 :'I.u"+y'

Try it online! Assumes the given predicate is a true boolean predicate, which yields 1 for truthy and 0 for falsey, as is standard in J.

I don't think there's a tacit way to make an adjective as complex as this. Technically, as per standard IO, we can have 8 bytes by assuming the function is stored in a predefined variable u:

[:I.u"+

Explanation

Approach c/o Razetime:

I.u"+y
  u      the given boolean function
   "+    applied at each cell of
     y   y, the input list
I.       obtain indices where truthy

Old approach:

u"0#i.@#
    i.     the indices from 0 to
      @#   the length of the input, right-exclusive
   #       and keeping only the elements corresponding to
u          the given boolean function
 "0        applied to each cell of the input
\$\endgroup\$
2
  • 1
    \$\begingroup\$ 1 :'I.u"0 y' is 12 \$\endgroup\$
    – Razetime
    Commented Oct 10, 2022 at 16:21
  • \$\begingroup\$ @Razetime Thank you! \$\endgroup\$ Commented Oct 10, 2022 at 16:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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