8
\$\begingroup\$

A ragged matrix, is a matrix that has a different number of elements in each row. Your challenge is to write a program in any favorable language to find the indices of all occurrences of target in the ragged matrix.

Input:

A list of ragged lists (can be empty) of positive integers and a target range e.g. 26-56. The target range, given 2 positive integers. For languages that do not support this type of list, you can input it as a string representation

You may assume that a<=b

Output:

If a number in the ragged list is within the range or equal to a or equal to b, output the index of the ragged list then the index of the number in that ragged list e.g. 0 4 - The 0 is the first ragged list in the input and the 4 is the index of the number in the first ragged list

Test cases:

[[[1,3,2,32,19],[19,2,48,19],[],[9,35,4],[3,19]],19-53]
->
[[0,3],[0,4],[1,0],[1,2],[1,3],[3,1],[4,1]]

[[[1,2,3,2],[],[7,9,2,1,4]],2-2]
->
[[0,1],[0,3],[2,2]]

You can choose to follow the output format above or output it in the following as well:

[[[1,3,2,32,19],[19,2,48,19],[],[9,35,4],[3,19]],19-53]
->
0 3 0 4 1 0 1 2 1 3 3 1 4 1

0-based and 1-based indexing is allowed

You can output your answers in any way as long as it is distinguishable what the indexes of the number and matrix are

You may assume the integers in the list are always positive and non-zero

This is code-golf, so shortest code wins!

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Can we assume the input integers are strictly positive (i.e. never zero)? \$\endgroup\$
    – Adám
    Jan 27, 2022 at 7:45
  • \$\begingroup\$ You may assume a<=b. Then why example is 56-26? \$\endgroup\$
    – tsh
    Jan 27, 2022 at 7:46
  • \$\begingroup\$ May I choose to input the range as a range object in python? (e.g. range(26,57) for 26-56) \$\endgroup\$
    – tsh
    Jan 27, 2022 at 7:46
  • \$\begingroup\$ typo @tsh sry for about that and yes i think that will be fine to use range but isnt it shorter to not use it? \$\endgroup\$
    – DialFrost
    Jan 27, 2022 at 7:48
  • 4
    \$\begingroup\$ jelly's ŒṪ seems to be made for this challenge \$\endgroup\$
    – Razetime
    Jan 27, 2022 at 8:49

14 Answers 14

6
\$\begingroup\$

Wolfram Language (Mathematica), 23 bytes

Position[a_/;#<=a<=#2]&

Try it online!

Input [a, b][list]. Returns 1-indexed.

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

Jelly, 8 7 bytes

r/iⱮⱮŒṪ

Try it online!

Walkthrough

 /        Reduce input range list by
r         range
   ⱮⱮ     Foreach at depth 2
              (on the right argument)
  i           Find first index of RHS in LHS
              (Or, in this case, checks whether
               current item (RHS) is within range (LHS)? )
      ŒṪ  All truthy multidimensional indices
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Nice job. A great Jelly tip is that when you find yourself using @ to look for dyads that can do what you need of the one you're using but with swapped arguments. In this case, to save a byte I would do r/ċⱮⱮŒṪ. \$\endgroup\$ Jan 27, 2022 at 19:43
  • 1
    \$\begingroup\$ You can also use i instead of e@ if you only need truthy/falsey values instead of 1/0: Relevant tip \$\endgroup\$ Jan 27, 2022 at 19:44
5
\$\begingroup\$

APL (Dyalog Extended), 8 bytes

Full program. Prompts for range, then array.

⍸↑⎕∊¨…/⎕

Try it online!

Explained from the right:

 prompt (for range)

…/ reduce using the range function (gives enclosed list of all number in the range)

∊¨ check if the elements of each of the following lists are in the entire (because it is enclosed) range:

 prompt for array

 mix list of Boolean lists into a matrix, padding with Falses

 indices of Trues

\$\endgroup\$
2
  • \$\begingroup\$ that was quick nice using anon func \$\endgroup\$
    – DialFrost
    Jan 27, 2022 at 7:47
  • 1
    \$\begingroup\$ @DialFrost Well, not an anon func anymore. \$\endgroup\$
    – Adám
    Jan 27, 2022 at 7:58
5
\$\begingroup\$

R, 87 bytes

Or R>=4.1, 80 bytes by replacing the word function with a \.

function(l,a,b,`[`=lapply)cbind(rep(seq(l),lengths(w<-l[`%in%`,a:b][which])),unlist(w))

Try it online!


Solution shorter in R>=4.1:

R, 92 bytes

Or R>=4.1, 78 bytes by replacing two function occurrences with \s.

function(l,a,b)cbind(rep(seq(l),lengths(w<-lapply(l,function(x)which(x%in%a:b)))),unlist(w))

Try it online!


Outgolfed by @Giuseppe. See that answer for a detailed explanation and comparison of our approaches.

\$\endgroup\$
5
  • 2
    \$\begingroup\$ 78 bytes by avoiding sapply -- I didn't think I would ever use lengths and sequence in the same answer ... \$\endgroup\$
    – Giuseppe
    Jan 27, 2022 at 17:41
  • 2
    \$\begingroup\$ @Giuseppe - Wow, you're an R magician! Do you remember all these seemingly-wierd functions, or do you have a secret way to search for them? \$\endgroup\$ Jan 27, 2022 at 20:04
  • \$\begingroup\$ @Giuseppe, I think you should post it as a separate answer. \$\endgroup\$
    – pajonk
    Jan 27, 2022 at 20:05
  • 2
    \$\begingroup\$ @DominicvanEssen sequence comes up every now and again and I've been tyring to find a use for lengths with all the ragged-list questions of late (looks like pajonk beat me there though). I'll admit after a couple years of golfing in R I had a slow year at work so I tried to read through the docs for most base functions and every now and again some weird ones come up :-) \$\endgroup\$
    – Giuseppe
    Jan 27, 2022 at 20:25
  • \$\begingroup\$ @pajonk I'll post it separately with an explanation in a bit. \$\endgroup\$
    – Giuseppe
    Jan 27, 2022 at 20:25
4
\$\begingroup\$

Python 3, 69 bytes

lambda l,r,e=enumerate:[[X,Y]for X,x in e(l)for Y,y in e(x)if y in r]

Try it online!

-3 thanks to @tsh

\$\endgroup\$
2
  • 3
    \$\begingroup\$ 69 if accept input as a range object: lambda l,r,e=enumerate:[[X,Y]for X,x in e(l)for Y,y in e(x)if y in r] \$\endgroup\$
    – tsh
    Jan 27, 2022 at 8:11
  • \$\begingroup\$ @tsh thanks a lot!! \$\endgroup\$
    – Wasif
    Jan 27, 2022 at 16:23
3
\$\begingroup\$

K (ngn/k), 13 bytes

{+&~(y+!2)'x}

Try it online!

Takes the ragged matrix as x (first arg, a list of lists) and the range as y (second arg, a pair of integers).

  • (y+!2) convert the range from e.g. 19 53 to 19 54 (to do a [lb;ub] comparison rather than [lb;ub))
  • (...)'x do a binary lookup of x in the list generated by (...). if a value in x is between the (adjusted) indices, 0 is returned
  • ~ not the above; values within the range become 1 and all others 0
  • & use "deep-where" to return indices of 1's
  • + transpose the result

It's likely that the final + (transpose) can be elided depending on what constitutes acceptable output.

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

R, 78 bytes

function(l,a,b)cbind(rep(seq(l),L<-lengths(l)),sequence(L))[unlist(l)%in%a:b,]

Try it online!

Originally posted as a comment on pajonk's answer, so uses that test harness. That answer is a very natural way to approach the problem in R, so if I hadn't peeked first, I probably wouldn't have found this gem.

Using R-style indexing, a single value in l is l[[i]][j], i.e., the jth (vector) element of the ith element of the list l. pajonk's answer generates a list of all the indices j for each i such that l[[i]][j] %in% a:b and then joins them with an appropriately-sized list of i, as below:

function(l,a,b){
in_ab <- sapply(l,`%in%`,a:b)		# for each element of l, return TRUE/FALSE where elements are in a..b
j_idx_list <- sapply(in_ab,which)	# now return the 1-based indices of the TRUE values
j_idx <- unlist(j_idx_list)		# and collapse into a single vector
i_lengths <- lengths(j_idx_list)	# take the # of valid j-indices in each sublist
i_idx <- rep(seq(l),i_lengths)		# and generate i-indices to match
cbind(i_idx,j_idx)			# and combine
}

This answer instead uses some functions rarely used in golfing, sequence and lengths to generate all the valid pairs i,j and then filters them directly. In fact, sequence is such an odd function in R that the docs used to say1 that "it mainly exists in reverence to the very early history of R", as I have mentioned before.

Ungolfed a bit:

function(l,a,b){
L <- lengths(l)			# find the lengths of each element of l
j_idx <- sequence(L)		# for each Length h, generate 1..h and append them together in order
i_idx <- rep(seq(l),L)		# replicate each of 1..length(l) times equal to the length of l[[i]]
filter_idx <- unlist(l)%in%a:b	# index for filtering
cbind(i_idx,j_idx)[filter_idx,]	# combine i,j indices as columns of a matrix, and filter the rows
}

1 Starting in version 4.0.0, sequence was updated to accept a from and by argument, much like seq, and this line was removed.

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

05AB1E, 13 (or 7?) bytes

εNUεIŸsåiXN‚?

First input is the matrix; second the range as pair of integers.
Outputs pairs of 0-based indices without delimiter to STDOUT.

Try it online or verify all test cases.

Not sure if this is a valid output-format:

ŸIåεƶ0K

First input is the range as pair of integers; second the matrix.
Outputs the 1-based truthy indices of each row.

Try it online or verify all test cases.

Explanation:

ε           # Map over each row of the (implicit) first input-matrix:
 NU         #  Store the row-index in variable `X`
 ε          #  Map over each integer in the row:
  I         #   Push the second (implicit) input-pair
   Ÿ        #   Convert it to an inclusive ranged list
    såi     #   If the current integer is in this list:
       XN‚  #    Pair `X` with the inner map-index
          ? #    Pop and output it

Ÿ           # Convert the (implicit) first input-pair to an inclusive ranged list
 I          # Push the second input-matrix
  å         # Check for each inner-most value if it's within this range
   ε        # Map over these integers:
    ƶ       #  Multiply each value by its 1-based index
     0K     #  Remove all 0s
            # (after which the list of lists is output implicitly)
\$\endgroup\$
2
\$\begingroup\$

Charcoal, 34 bytes

≔⮌I⪪η-η≔…·⊟η⊟ηηFLθF⌕AE§θι№ηκ¹I⟦⟦ικ

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

≔⮌I⪪η-η≔…·⊟η⊟ηη

Convert the second input into a range.

FLθ

Loop over the sublists.

F⌕AE§θι№ηκ¹

Loop over the indices where the element lies within the range.

I⟦⟦ικ

Output the outer and inner indices on separate lines double-spaced between each pair of indices.

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

Factor, 71 bytes

[ '[ [ _ _ between? ] arg-where ] map <enumerated> expand-values-push ]

enter image description here

Explanation

  • '[ [ _ _ between? ] arg-where ] map Map the indices inside the range to each row of the ragged matrix.
  • <enumerated> Zip a list with its indices.
  • expand-values-push Combine each key with each of the elements in its value, collecting the results in a single list of pairs.
                                     ! { { 1 3 2 32 19 } { 19 2 48 19 } { } { 9 34 4 } { 3 19 } } 19 53
'[ [ _ _ between? ] arg-where ] map  ! { V{ 3 4 } V{ 0 2 3 } V{ } V{ 1 } V{ 1 } }
<enumerated>                         ! { { 0 V{ 3 4 } } { 1 V{ 0 2 3 } } { 2 V{ } } { 3 V{ 1 } } { 4 V{ 1 } } }
expand-values-push                   ! V{ { 0 3 } { 0 4 } { 1 0 } { 1 2 } { 1 3 } { 3 1 } { 4 1 } }
\$\endgroup\$
2
\$\begingroup\$

JavaScript (V8), 58 56 bytes

(a,l,r)=>a.map((x,i)=>x.map((y,j)=>l>y|y>r||print(i,j)))

Try it online!

Saved 2 bytes thanks to Arnauld.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ l<=y&y<=r&& can be turned into l>y|y>r|| \$\endgroup\$
    – Arnauld
    Jan 27, 2022 at 21:12
2
\$\begingroup\$

Vyxal, 12 bytes

ṫ÷r£hƛ¥vc;ÞT

Try it Online!

Needs input in form: [<main_arr>, [a, b]]

ṫ            # Get [a, b]
 ÷r          # Get range a..b
   £         # Set to register
    h        # Main array
     ƛ       # Begin map
      ¥      # Push register
       vc    # Is item inside range (vectorized)
         ;ÞT # Close map and print truthy indices
\$\endgroup\$
1
\$\begingroup\$

Python3, 80 bytes

lambda l,a,b:[ [X,Y] for X,x in enumerate(l) for Y,y in enumerate(x) if a<=y<=b]

Try it online!

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

Scala, 112 bytes

for a 2d matrix, find all indices where element is between the Range.


Golfed version. Try it online!

def f(l:Seq[Seq[Int]],r:Range)={for{(x,i)<-l.zipWithIndex;(y,j)<-x.zipWithIndex if r.contains(y)}yield Seq(i,j)}

Ungolfed version. Try it online!

object PythonToScala {
  def main(args: Array[String]): Unit = {
    val l: List[List[Int]] = List(List(1, 3, 2, 32, 19), List(19, 2, 48, 19), List(), List(9, 35, 4), List(3, 19))
    val a: Int = 19
    val b: Int = 53

    def f(l: List[List[Int]], r: Range): List[List[Int]] = {
      for {
        (x, i) <- l.zipWithIndex
        (y, j) <- x.zipWithIndex if r.contains(y)
      } yield List(i, j)
    }

    println(f(l, a until b))
  }
}

\$\endgroup\$

Your Answer

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

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