22
\$\begingroup\$

(we won't be finding a Find or catching a tryCatch, though)

This is part two of a multi-part series of implementing some interesting R functions. Part one can be found here.

The task:

You are to implement R's match function in as few bytes as possible.

Input:

  • x, a possibly empty list/array of integers
  • table, a possibly empty list/array of integers
  • nomatch, a single integer value
  • incomparables, a possibly empty list/array of integers

Output:

  • a single array/list of integers O of equal length to x, where each value O[i] represents either:
    • The index j of the first value in table where table[j]==x[i]
    • nomatch, indicating that no value in table is equal to x[i] OR that x[i] is in the list of incomparables.

Test Cases

All in the form x, table, nomatch, incomparables -> output
outputs 

[], [1,2,3], 0, [5] -> []

[1, 2, 3], [], 0, [5] -> [0, 0, 0]

[9, 4, 3, 6, 3], [9, 8, 7, 6, 5, 4, 3, 2, 1], -1, [4] -> [1, -1, 7, 4, 7]

[8, 6, 7, 5, 3, 0, 9], [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6], 1000, [1] -> [12, 8, 14, 5, 1, 1000, 6]

More test cases can be generated as needed.

Additional rules:

  • R has 1-based indices, but a consistent alternative-based indices are acceptable. So you can use indices that start at 3 or 17 or whatever, but this must be consistent, and you must indicate this in your answer.
  • If you chosen language has a builtin that does this, please also implement your own solution.
  • Explanations are appreciated.

This is , so shortest solution in bytes wins!

\$\endgroup\$
4
  • \$\begingroup\$ Must it support negative numbers? I'll assume it doesn't need to, since only the example assumes it and I'm pretty sure there's a standard rule for it. \$\endgroup\$
    – wizzwizz4
    Commented Jul 11, 2019 at 11:01
  • \$\begingroup\$ @wizzwizz4 no, because 4 is in incomparables, so it can't be matched. If your language can't support negative numbers, then it's fine to require non-negative numbers, but state that assumption in your submission. \$\endgroup\$
    – Giuseppe
    Commented Jul 11, 2019 at 16:03
  • 1
    \$\begingroup\$ Addition to header comment: we also won't be making make. \$\endgroup\$ Commented Jul 12, 2019 at 21:16
  • 1
    \$\begingroup\$ @val it's actually a pretty bad reference to Fiddler on the Roof; all of these challenges have titled themed after various showtunes because this one fit so perfectly that I thought it would make a good theme. \$\endgroup\$
    – Giuseppe
    Commented Jul 13, 2019 at 15:09

17 Answers 17

9
+150
\$\begingroup\$

R, 83 bytes

function(x,t,n,i)sapply(x,function(a)c(which(a==t/!rowSums(outer(t,i,`==`))),n)[1])

Try it online!

Avoids match, %in% and setdiff.

\$\endgroup\$
1
  • 4
    \$\begingroup\$ 66 bytes \$\endgroup\$
    – JAD
    Commented Jul 12, 2019 at 13:24
8
\$\begingroup\$

Jelly,  10  8 bytes

-2 thanks to Erik the Outgolfer

,⁷y⁵iⱮ⁶o

A full program accepting four command line arguments, incomparables nomatch table x which prints a Jelly representation* of the list of R's match function results.

Try it online!

How?

e.g. with incomparables nomatch table x = [1,4], 2, [2,4], [4,3,2,1,0]:

,⁷y⁵iⱮ⁶o - Main Link: list, incomparables; list, nomatch
 ⁷       - newline character                                '\n'
,        - pair (incompararables) with (right)              [[1,4],'\n']
   ⁵     - 5th argument (3rd input = table)                 [2,4]
  y      - translate (right) with lookup (left)             [2,'\n']             
      ⁶  - 6th argument (4th input = x)                     [4,3,2,1,0]
     Ɱ   - map with:
    i    -   first index of (right) in (left)               [0,0,1,0,0]
       o - logical OR                                       [2,2,1,2,2]

* An empty list is represented as nothing, a list of lenth one is represented as just the item, while other lists are enclosed in [] and delimited by ,

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

R, 55 bytes

In this case, the code doesn't use match with its full functionality, it is just used as an index function. First R answer, so probably incredibly inefficient byte-wise!

Note (thanks to Giuseppe for the info): %in% and setdiff are also both internally implemented using match, so completely getting rid of this surprisingly useful function will result in a mess. Therefore, there is a 150-rep bounty with no deadline for this! (note that setdiff is allowed, though)

function(x,t,n,i)ifelse(x%in%setdiff(t,i),match(x,t),n)

Try it online!

or...

R, 5 bytes

match

Try it online!

\$\endgroup\$
11
  • \$\begingroup\$ I'm not sure I could do better although I was eschewing the use of %in% and match; if you want to find a good golfy answer without either of those functions (likely to be horrible), I'll bounty this. \$\endgroup\$
    – Giuseppe
    Commented Jul 10, 2019 at 19:28
  • \$\begingroup\$ Ah lol, I just commented in golfR about that... \$\endgroup\$
    – Mr. Xcoder
    Commented Jul 10, 2019 at 19:30
  • \$\begingroup\$ Upvoted solely for the snarky match submission \$\endgroup\$ Commented Jul 11, 2019 at 18:48
  • \$\begingroup\$ You can shorten ifelse using this tip: codegolf.stackexchange.com/a/97826/59530 \$\endgroup\$
    – JAD
    Commented Jul 12, 2019 at 13:07
  • 2
    \$\begingroup\$ also, your longer submission actually uses match :S \$\endgroup\$
    – JAD
    Commented Jul 12, 2019 at 13:07
6
\$\begingroup\$

Jelly, 9 8 bytes

ṣK¥ƒiⱮo⁶

Try it online!

A full program that takes three arguments: [[table], incomparables], x, nomatch in that order.

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

C# (Visual C# Interactive Compiler), 60 bytes

(a,b,c,d)=>a.Select(x=>d.Contains(x)|(x=b.IndexOf(x))<0?c:x)

Try it online!

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

Ruby, 44 bytes

Zero-indexed.

->x,t,n,i{x.map{|e|i-[e]==i&&t.index(e)||n}}

Try it online!

\$\endgroup\$
5
+300
\$\begingroup\$

R, 79 bytes

function(x,t,n,i)sapply(x,function(y)`if`(any(z<-y==t)&all(y-i),which(z)[1],n))

Try it online!

R, 66 bytes

function(x,t,n,i)sapply(x,function(y)c(which(y==t&all(y-i)),n)[1])

Combining my solution with parts of Nick's solution.

Try it online!

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

Japt, 14 bytes

Ë!XøD ©ÒVbD ªW

Try it

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

Python 3, 60 bytes

lambda x,t,n,i:[v in{*t}-{*i}and-~t.index(v)or n for v in x]

Try it online!

\$\endgroup\$
6
  • \$\begingroup\$ What features of this are specific to 3.8? Looks to me like this could work for any subversion of Python 3. \$\endgroup\$
    – Theo
    Commented Jul 10, 2019 at 18:45
  • \$\begingroup\$ Well, it is not specific to 3.8. I just copy-pasted the auto-generated template on TIO so I didn't notice I used 3.8. Thanks for the heads-up, will adjust. \$\endgroup\$
    – Mr. Xcoder
    Commented Jul 10, 2019 at 18:46
  • 1
    \$\begingroup\$ R has 1-based indices, but a consistent alternative-based indices are acceptable. So you can take out the -~ and just use 0-indexing for -1 bytes. \$\endgroup\$
    – Value Ink
    Commented Jul 10, 2019 at 18:46
  • 1
    \$\begingroup\$ @ValueInk That fails for the 3rd test case (and in general when a matching element is at the beginning of a list), since 0 is falsy in Python. \$\endgroup\$
    – Mr. Xcoder
    Commented Jul 10, 2019 at 18:48
  • 1
    \$\begingroup\$ Ah, fair show. Incidentally, t.index(v)if v in{*t}-{*i}else n has the exact same bytecount as your current v in{*t}-{*i}and-~t.index(v)or n solution, haha \$\endgroup\$
    – Value Ink
    Commented Jul 10, 2019 at 18:57
4
\$\begingroup\$

PowerShell, 63 bytes

param($x,$t,$n,$o)$x|%{($n,$t.indexof($_))[$_-in$t*!($_-in$o)]}

Try it online!

0-indexed

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

JavaScript (ES6), 53 bytes

(x,t,n,i)=>x.map(v=>!~i.indexOf(v)*-~t.indexOf(v)||n)

Try it online!

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

Perl 6, 45 bytes

->\b,\c,\d{*>>.&{$_∉d&&~b.first($_,:k)||c}}

Try it online!

Anonymous code block that takes input curried, like f(table, nomatch, incomparables)(x) and returns the matches 0 indexed.

Explanation:

->\b,\c,\d{                               }    # Anonymous code block taking 3 inputs
           *           # Return an anonymous Whatever lambda
            >>.&{                        }  # Mapping input to
                 $_∉d                       # If the element is not an uncomparable
                     && b.first($_,:k)      # Return the first index in the table
                       ~                    # Stringified so Nils are false
                                      ||c   # Else the nomatch element
~~
\$\endgroup\$
1
  • \$\begingroup\$ +1 I worked on this briefly but was doing $_∉d&&b.antipairs.Map{$_}||c which would have worked well but for the falsey value of 0. The first($_:k) is a great solution that avoids the long antipairs.Map coercion. \$\endgroup\$ Commented Jul 16, 2019 at 11:23
2
\$\begingroup\$

Charcoal, 14 bytes

IEθ∨∧¬№ει⊕⌕ηιζ

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

  θ             First input (x)
 E              Map over elements
       ε        Fourth input (incomparables)
      №         Count occurrences of
        ι       Current element
     ¬          Is zero
    ∧           Logical And
           η    Second input (table)
          ⌕     Find 0-based index of
            ι   Current element
         ⊕      Convert to 1-indexed
   ∨            Logical Or
             ζ  Third input (nomatch)
I               Cast to string
                Implicitly print on separate lines
\$\endgroup\$
2
\$\begingroup\$

C (gcc), 125 bytes

1-indexed.

Given that I can't use a sentinel value in the passed arrays, I need to give the array bounds for each array.

f(x,c,t,d,n,i,e,j,f)int*x,*t,*i;{for(;f=0,c-->0;x[c]=--f?n:j){for(j=e;!f&j;x[c]-i[--j]||--f);for(;!f&j<d;x[c]-t[j++]||++f);}}

Try it online!

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

Attache, 39 bytes

${{[_,y][nil=_or x@_in z]}=>x&Index@_4}

Try it online!

Pretty simple verification. Note that the argument order differs from that of match; specifically, x is the last argument rather than the first, and corresponds to _4 in the above snippet.

Explanation

${{[_,y][nil=_or x@_in z]}=>x&Index@_4}
${                                    }   named lambda, taking parameters x, y, z, and _4
                            x&Index@_4    short for Index[x, _4];
                                              calculates where each element in _4 occurs in x
                                              returns `nil` for no match
  {                      }=>              over each index:
   [_,y][               ]                     choose y (`nomatch`) if
         nil=_                                    the index is nil
              or x@_in z                          or the element is in `incomparables`
    _                                         otherwise, choose the index
\$\endgroup\$
2
\$\begingroup\$

Haskell, 57 56 bytes

(t#n)i=map$maybe n id.($zip i[n,n..]++zip t[1..]).lookup

Argument order is: table, nomatch, incomparables, x.

Try it online!

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

05AB1E, 7 bytes

õ:Ik®I:

0-indexed. Inputs are in the order: incomparables, table, x, nomatch.

Try it online.

Explanation:

õ:       # Replace all values of the (implicit) first incomparables-list in
         # the (implicit) second table-list with an empty string
         #  i.e. incomparables=[4] and table=[9,8,7,6,5,4,3,2,1] → [9,8,7,6,5,"",3,2,1]
  Ik     # Get the index of each value in the third x-list in this list (-1 if not found)
         #  i.e. x=[9,4,3,6,3] → [0,-1,6,3,6]
    ®I:  # Replace all -1 with the fourth input-integer
         #  i.e. nomatch=-99 → [0,-99,6,3,6]
         # (and output the mapped list implicitly as result)
\$\endgroup\$

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.