16
\$\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
    Jan 19 at 9:58
  • 3
    \$\begingroup\$ husk,1 byte: W \$\endgroup\$
    – Razetime
    Jan 19 at 10:17
  • \$\begingroup\$ Just out of curiosity, is there any language that actually has a function called "argwhere"? \$\endgroup\$
    – ophact
    Jan 19 at 10:18
  • \$\begingroup\$ @ThisFieldIsRequired Yep! See docs.factorcode.org/content/… \$\endgroup\$
    – chunes
    Jan 19 at 10:24
  • \$\begingroup\$ Are we allowed to output the indices in reversed order? \$\endgroup\$ Jan 19 at 10:49

27 Answers 27

10
\$\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
    Jan 19 at 10:18
  • 1
    \$\begingroup\$ @DialFrost Is it the best one possible, though? \$\endgroup\$
    – ophact
    Jan 19 at 10:19
  • \$\begingroup\$ maybe im trying it out right now \$\endgroup\$
    – DialFrost
    Jan 19 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
    Jan 20 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
    Jan 20 at 3:03
8
\$\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
    Jan 20 at 14:23
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
    Jan 19 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\$

Java 8, 74 bytes

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

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

Try it online.

Explanation:

f->a->{               // Method with Function & integer-array parameter and no
                      // return-type
  for(int i=0;i<a.length;i++)
                      //  Loop `i` in the range [0,length):
    if(f.apply(a[i])) //   If the Function for the `i`'th integer is truthy:
      System.out.println(i);}
                      //    Print index `i` with trailing newline
\$\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\$

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\$
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
    Jan 19 at 23:37
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
    Jan 19 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\$ Jan 19 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\$ Jan 19 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\$

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\$

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\$

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\$
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
    Jan 19 at 10:12
  • \$\begingroup\$ @thisFieldIsRequired Thanks. \$\endgroup\$
    – Cool guy
    Jan 19 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
    Jan 19 at 10:23
  • \$\begingroup\$ @ovs You're indeed correct, fixed. \$\endgroup\$ Jan 19 at 10:26
2
\$\begingroup\$

Ruby, 35 bytes

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

Attempt This Online!

\$\endgroup\$
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\$

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\$
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\$
1
\$\begingroup\$

[Fortran], 180 bytes

Since there are anonymous functions for other languages allowed, I assume that I can name my argwhere function with a letter and make use of the implicit typing.

function J(v,n,f)
integer v(*)
interface
logical function g(m)
end function
end interface
procedure(g) f
allocatable J(:)
J = pack([(i,i=1,n)],mask=[(f(v(i)),i=1,n)])
end function

An ungolfed version looks like this.

program test_argwhere
    implicit none
    abstract interface
        logical pure function predicate_t(n)
            integer, intent(in) :: n
        end function
    end interface


    write(*, *) argwhere([1, 3, 4, 8, 5], is_even)

contains

    pure function argwhere(vals, predicate) result(res)
        integer, intent(in) :: vals(:)
        procedure(predicate_t) :: predicate
        integer, allocatable :: res(:)
        integer :: i
        res = pack([(i, i = 1, size(vals))], mask=[(predicate(vals(i)), i = 1, size(vals))])
    end function

    logical pure function is_even(n)
        integer, intent(in) :: n
        is_even = mod(n, 2) == 0
    end function

end program
```
\$\endgroup\$
1
\$\begingroup\$

Kotlin, 72 61 bytes

fun <T> List<T>.f(p:(T)->Boolean)=indices.filter{p(this[it])}

0-based solution.

Uses built-in indices to perform a filter on.

Example:

fun main() {
    println(listOf(1, 2, 0, 0, 3, 0, 0, 0, 4).f { it == 0 })
}
\$\endgroup\$
1
\$\begingroup\$

F#, 79 bytes

let x a p = a|>Seq.mapi(fun i a -> i,a)|>Seq.filter(fun(_,a)->p a)|>Seq.map fst
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Welcome to Code Golf! Can you save any bytes by removing spaces? \$\endgroup\$ Jan 21 at 14:27
  • \$\begingroup\$ I mean, yeah, but it hurts my head :) \$\endgroup\$ Jan 21 at 17:24

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.