19
\$\begingroup\$

Given two strings: a string s and an alphabet a, implement string projection in the shortest code possible.

String projection returns a string o that contains the characters in s that are in a. The order of the characters in o must match the order of characters in s. So if s = "abcd" and a = "12da34", o = "ad", since only "ad" is shared between s and a.

You will need to handle when a is empty (outputs empty string, since no character in s can match empty string).

Test Cases

"string", "alphabet" => "output"
-------------------------------
"abcd", "12da34" => "ad"
"hello, world!", "aeiou" => "eoo"
"hello, world!", "abcdefghijklmnopqrstuvwxyz" => "helloworld"
"Hello, World!", "abcdefghijklmnopqrstuvwxyz" => "elloorld" (case sensitivity)
"Hello, World!", "abcdef" => "ed"
"Hello, World!", "!,. \n\t" => ", !" (newline, tab)
"172843905", "abc123" => "123"
"fizzbuzz", "" => ""
"fizzbuzz", "fizzbuzz" => "fizzbuzz"
"", "fizzbuzz" => ""
"fizzbuzz", "zzzzz" => "zzzz"
"", "" => "" (two empty strings)

Winning Criteria

This is , so shortest code wins!

asked Aug 7, 2022 at 16:41
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Surprised by how many golflangs have a builtin or two for this task \$\endgroup\$ Commented Aug 10, 2022 at 8:51
  • 1
    \$\begingroup\$ prolog builtin is intersection/3 \$\endgroup\$ Commented Sep 7, 2022 at 14:16

47 Answers 47

1
2
11
\$\begingroup\$

Rust, 20 bytes

str::matches::<&[_]>

Attempt This Online!

This mixes up three I/O methods for strings: the first parameter is a plain string slice &str, the second is a slice of chars &[char], and the output is an iterator yielding single-char string slices impl Iterator<Item=&str>.

Doc for str::matches. It can take several kinds of patterns (i.e. anything that implements Pattern) for non-overlapping substring search:

  • single char: matches that char
  • a &str or equivalent: matches that exact string
  • a slice of chars &[char] or equivalent: matches any char out of the ones listed
  • (and any 3rd party type that implements Pattern, e.g. Regex)

We use the third variety in this challenge, which is indicated by the ::<&[_]> part. _ is a kind of wildcard type, and it resolves to char by the compiler because &[char] is the only type matching &[_] that implements Pattern.

answered Aug 8, 2022 at 0:39
\$\endgroup\$
9
\$\begingroup\$

Regex (ECMAScript or better), 20 bytes

s/(.)(?!.*␀.*1円)//sg

Try it online! - ECMAScript 2018
Try it online! - Perl
Try it online! - PCRE2
Try it online! - Boost
Try it online! - Python
Try it online! - Ruby
Try it online! - .NET

This is a single regex substitution, to be applied once. Input is taken in the form of the two strings delimited by NUL (ASCII 0).

Above and below, represents what is actually a raw NUL character in the regex.

s/ # Begin substitution - match the following:
 (.) # 1円 = one character
 (?! # Negative lookahead - match if the following can't match:
 .* # Skip over as many characters as possible, minimum zero, to make
 # the following match:
 ␀ # Skip over the NUL delimiter
 .* # Skip over as many characters as possible, minimum zero, to make
 # the following match:
 1円 # Match the character we captured in 1円
 )
/ # Substitution - replace with the following:
 # Empty string
/ # Flags:
s # single line - "." will match anything, including newline
g # global - find and replace all matches, going from left to right

This automatically erases the NUL and everything following it, because NUL and all characters following it are themselves not followed by NUL, so the negative lookahead matches for each of them.

(More test harnesses to come.)

As far as ECMAScript goes, this requires ECMAScript 2018 (aka ES9) due to the use of the s flag.

In Ruby, the m flag is used, which is the Ruby equivalent of what is s in most other regex engines.

\$\large\textit{Anonymous functions}\$

Perl, 42 bytes

sub{$_=join'␀',@_;s/(.)(?!.*␀.*1円)//sg;$_}

Try it online!

Takes the two strings as arguments.

Beaten by a 35 byte solution based on an unposted solution by Sisyphus: Try it online!

Ruby, (削除) 42 (削除ここまで) 41 bytes

-1 byte thanks to Steffan

->s,a{(s+?␀+a).gsub /(.)(?!.*␀.*1円)/m,''}

Try it online!

PowerShell, 42 bytes

$args-join'␀'-creplace'(?s)(.)(?!.*␀.*1円)'

Try it online!

Takes the two strings as arguments.

JavaScript (ES9), 43 bytes

a=>a.join`␀`.replace(/(.)(?!.*␀.*1円)/sg,'')

Try it online!

Takes a list containing the two strings.

Java, 52 bytes

s->a->(s+"␀"+a).replaceAll("(?s)(.)(?!.*␀.*\1円)","")

Attempt This Online!

\$\large\textit{Full programs}\$

Perl, 37 bytes

$_=join'',<>;s/(.)(?!.*␀.*1円)//sg;say

Try it online!

Takes multiline input (terminated by EOF) using NUL as a delimiter between the two strings.

Beaten by a 19 byte solution based on an unposted solution by Sisyphus: Try it online! (they should really post it), or 25 bytes to insert chomp; at the beginning if being picky about the output being followed by a NUL.

answered Aug 7, 2022 at 18:55
\$\endgroup\$
8
\$\begingroup\$

Jelly, 1 byte

f

Try it online!

This is exactly what Jelly's "filter-keep" dyadic atom does - takes a list on the left and a list on the right and keeps those in the left that appear in the right.

answered Aug 7, 2022 at 17:48
\$\endgroup\$
8
\$\begingroup\$

Haskell, 16 bytes

filter.flip elem

Try it online!

Takes arguments in reverse order.

answered Aug 7, 2022 at 21:29
\$\endgroup\$
5
\$\begingroup\$

R, 15 bytes

\(s,a)s[s%in%a]

Attempt This Online!

Takes input and outputs through vectors of character codes (as in linked test suite) or vectors of characters.

answered Aug 7, 2022 at 19:23
\$\endgroup\$
5
\$\begingroup\$

Brachylog, 4 bytes

dt∋v

Try it online!

Takes a list [s, a], and generates a list constituting the projection.

dt Deduplicate a,
 ∋v then yield some c from a pair of elements [c, c] from s and a.

Deduplicating a is necessary in order to not generate multiple pairs from the same element of s.

answered Aug 7, 2022 at 22:27
\$\endgroup\$
5
\$\begingroup\$

K (ngn/k), 4 bytes

Uses set difference (^) to compute the intersection: x∩y = x-(x-y)

^/^\

Try it online!

answered Aug 8, 2022 at 22:33
\$\endgroup\$
5
\$\begingroup\$

C (clang) -m32, (削除) 54 53 (削除ここまで) 45 bytes

-1 byte thanks to @ceilingcat
-8 bytes thanks to @jdt

f(*s,a){for(;*s;)write(1,s,!!index(a,*s++));}

Try it online!

Explanation

f(*s,a){ // function f() takes a wide-character string (s) and an int (a)
 for(;*s;) // while we're not at the end of the string
 write(1,s,N // write N bytes from s to stdout
 !!<expr> // if <expr> is NULL, return 0, otherwise 1
 index(a,c // if the character `c` is found in `(const char *) a`,
 // return a pointer to it's occurrence, otherwise `NULL`
 *s++ // return the current character and increment s
 ) // end call to index(3)
 ); // end call to write(2)
} // end function f()

Caveat

There is undefined behavior in the form of an unsequenced modification and access to s, but clang happened to evaluate s (the second parameter to write) before incrementing it in the call to index(3) so in this case it works.

answered Aug 7, 2022 at 18:22
\$\endgroup\$
3
  • \$\begingroup\$ 45 bytes \$\endgroup\$ Commented Aug 19, 2022 at 12:51
  • \$\begingroup\$ sizeof a needs to be 8, otherwise it would segfault if the string is on the stack, or any address that doesn't fit in an int \$\endgroup\$ Commented Aug 19, 2022 at 14:30
  • \$\begingroup\$ You can change it to f(*s,*a)(... if you really want to. \$\endgroup\$ Commented Aug 19, 2022 at 14:37
4
\$\begingroup\$
answered Aug 7, 2022 at 17:42
\$\endgroup\$
4
\$\begingroup\$

Pip, 5 bytes

a@X^b

Try It Online!

Explanation

 b Second command-line argument
 ^ Split into characters
 X Convert to regex that matches any of those characters
 @ Find all matches of the regex in
a First command-line argument

By default, the list of matches is concatenated together and output.

answered Aug 9, 2022 at 15:31
\$\endgroup\$
4
\$\begingroup\$

Python, (削除) 35 (削除ここまで) 28 bytes

lambda a,b:filter(b.count,a)

Attempt This Online!

Takes in either strings or lists of characters, outputs a list of characters.


-7 bytes from @dingledooper by using filter + count instead of list comprehension and in

answered Aug 7, 2022 at 16:58
\$\endgroup\$
4
  • 5
    \$\begingroup\$ 28 bytes \$\endgroup\$ Commented Aug 7, 2022 at 21:32
  • \$\begingroup\$ Don't think it works, @dingledooper: ATOL. Think that list comprehension was right, tho. \$\endgroup\$ Commented Aug 14, 2022 at 0:52
  • \$\begingroup\$ After correcting the "filter-count" method to join the characters into a string, it comes out at 37 chars. \$\endgroup\$ Commented Aug 14, 2022 at 1:06
  • 1
    \$\begingroup\$ @dsillman2000 filter returns a generator, so it doesn't work unless you unpack it as a list, such as with [*a]. And according to meta, it's considered an accepted form of output. \$\endgroup\$ Commented Aug 14, 2022 at 1:12
4
\$\begingroup\$

sh + coreutils, 6 bytes

tr -cd

Takes string s from stdin, alphabet a as an argument.

answered Aug 7, 2022 at 18:02
\$\endgroup\$
3
  • \$\begingroup\$ Incomplete code snippet. An actually useful function using tr is at least 14 bytes. Attempt this online! \$\endgroup\$ Commented Dec 25, 2022 at 10:31
  • \$\begingroup\$ It is not a function, it's a shell command. Inputs are not given as function arguments, but as specified (s from stdin, a as a third argument). \$\endgroup\$ Commented Dec 25, 2022 at 10:39
  • 1
    \$\begingroup\$ @roblogic see codegolf.meta.stackexchange.com/a/5415/73593 \$\endgroup\$ Commented Dec 25, 2022 at 10:44
3
\$\begingroup\$

Factor, 6 bytes

within

Try it online!

answered Aug 7, 2022 at 22:32
\$\endgroup\$
3
\$\begingroup\$

C#, 33 bytes

(s,t)=>s.Where(c=>t.Contains(c));

Try it online!

answered Aug 8, 2022 at 14:35
\$\endgroup\$
3
\$\begingroup\$

BQN, 3 bytes

∊/⊣

Try it at BQN REPL

 / # Replicate elements of 
 ⊣ # left argument
 # by
∊ # 1 if each element of left argument is in right argument
 # 0 otherwise
answered Aug 8, 2022 at 21:54
\$\endgroup\$
2
\$\begingroup\$

PARI/GP, 27 bytes

f(a,b)=[c|c<-a,[d==c|d<-b]]

Attempt This Online!

Input and output lists of characters.

answered Aug 8, 2022 at 0:02
\$\endgroup\$
2
\$\begingroup\$

05AB1E, 1 byte

Ã

Another 1-byte builtin. Takes the inputs in the order alphabet,string.

Try it online or verify all test cases.

answered Aug 8, 2022 at 8:50
\$\endgroup\$
2
\$\begingroup\$

JavaScript (Node.js), 44 bytes

s=>a=>[...s].filter(c=>a.includes(c)).join``

Try it online!

Unfortunately, using .filter(a.includes) for 38 (wow!) throws String.prototype.includes called on null or undefined

answered Aug 8, 2022 at 12:22
\$\endgroup\$
2
  • 1
    \$\begingroup\$ The output from that test harness is a bit hard to read, so for convenience: Try it online! \$\endgroup\$ Commented Aug 8, 2022 at 19:38
  • 1
    \$\begingroup\$ And in any case, nice answer! I find it quite interesting how close in length it is to my regex one. \$\endgroup\$ Commented Aug 8, 2022 at 19:41
2
\$\begingroup\$

CJam, 10 bytes

Loosely inspired by this answer to another challenge.

l~:A;{A&}/

Input is a line containing the two strings separated by a space. If a string contains special characters it needs to be defined explicitly as an array of chars.

Try it online! Or verify all test cases.

How it works

l~ e# Read line and evaluate: pushes the two strings onto the stack
 :A; e# Copy the second string into variable A, then pop
 { }/ e# For each character in the first string, do the following
 e# Implicitly push current character of the first string
 A e# Push the second string
 & e# Set intersection. This gives the current char or an empty string
 e# Implicitly display stack contents
answered Aug 8, 2022 at 22:51
\$\endgroup\$
2
\$\begingroup\$

Nibbles, 2 bytes (4 nibbles)

|@?@
| # filter
 @ # the (second) input array
 # for truthy results of the function:
 ? # index (or 0 if not found) 
 @ # in the (first) input array

enter image description here

answered Aug 9, 2022 at 9:08
\$\endgroup\$
2
\$\begingroup\$

Charcoal, 5 bytes

ΦθNoηι

Try it online! Link is to verbose version of code. Explanation: Trivial port of @dingledooper's golf to adam's Python answer.

 θ First input
Φ Filtered where
 No Count of
 ι Current character
 η In second input
 Implicitly print

Newlines and other unprintables need to be entered using JSON format.

answered Aug 8, 2022 at 11:31
\$\endgroup\$
2
  • \$\begingroup\$ 30 bytes or 5 bytes? \$\endgroup\$ Commented Aug 9, 2022 at 11:26
  • \$\begingroup\$ @DominicvanEssen Whoops, I'm trying to do this on a tablet and forgot to update from the verbose to the succinct byte count. \$\endgroup\$ Commented Aug 9, 2022 at 11:44
2
\$\begingroup\$

Raku, 22 bytes

{$^a.trans($^b=>""):c}

Try it online!

trans is Raku's beefed-up version of Perl 5's transliteration operator tr.

answered Aug 12, 2022 at 17:21
\$\endgroup\$
2
\$\begingroup\$

Ruby, 29 bytes

->s,a{s.gsub(/./){a[_1]&&_1}}

Previous version which had flaws indicated by Deadcode:

->s,a{s.tr(s.tr(a,""),"")}

Try it online!

answered Aug 13, 2022 at 14:40
\$\endgroup\$
4
  • 2
    \$\begingroup\$ tr parses a like a regex character class; ranges (e.g. a-z) are parsed, and ^ at the beginning negates. So this answer is incorrect unless a can be quoted/escaped in such a way that no characters are treated specially. \$\endgroup\$ Commented Aug 13, 2022 at 20:40
  • \$\begingroup\$ Welcome to Code Golf! \$\endgroup\$ Commented Aug 13, 2022 at 22:29
  • \$\begingroup\$ Nice. This can be shortened further, to 25 bytes: Attempt This Online! \$\endgroup\$ Commented Aug 13, 2022 at 23:44
  • \$\begingroup\$ Also, 27 byte version that works on the older Ruby version on TIO: Try it online! \$\endgroup\$ Commented Aug 13, 2022 at 23:49
1
\$\begingroup\$

Haskell, 20 bytes

a#b=filter(`elem`b)a
answered Aug 7, 2022 at 18:00
\$\endgroup\$
1
\$\begingroup\$

Rust, 70 bytes

|a:&str,b:&[u8]|a.bytes().filter(|d|b.contains(d)).collect::<Vec<_>>()

Attempt This Online!

answered Aug 7, 2022 at 18:26
\$\endgroup\$
1
\$\begingroup\$

Vyxal r, 3 bytes

F1F

Try it Online!

Unfortuantely, the builtin doesn't work with duplicates.

answered Aug 7, 2022 at 19:47
\$\endgroup\$
1
\$\begingroup\$

Knight, 63 bytes

;=aP;=bP Wa;=c b;=dF;Wc;I?AcAa=dT0=cGc 1Lc;IdO+A Aa"\"0=aGa 1La

Try it online!

answered Aug 7, 2022 at 21:48
\$\endgroup\$
1
  • \$\begingroup\$ You didn't edit this into the list of answers. \$\endgroup\$ Commented Aug 8, 2022 at 20:54
1
\$\begingroup\$

Wolfram Language (Mathematica), 16 bytes

Cases[#|##&@@#]&

Try it online!

Input and output two lists of characters [alphabet][string].

answered Aug 7, 2022 at 22:45
\$\endgroup\$
1
\$\begingroup\$

MATLAB, 25 bytes

f=@(a,b)a(ismember(a,b))

Technically, only the call of a(ismember(a,b)) is required to fulfill the task, but to make it a callable function a function handle is created. Also, the inputs have to be of type char, not string, as a char is an array whereas a string is more like a complete unit in MATLAB.

Try it online!

answered Aug 8, 2022 at 12:32
\$\endgroup\$
1
  • 1
    \$\begingroup\$ You don't need to count f= (an anonymous function is valid) or the final linefeed: tio.run/##y08uSSxL/… \$\endgroup\$ Commented Aug 8, 2022 at 21:37
1
\$\begingroup\$

Haskell, 21 bytes

s#a=[c|c<-s,elem c a]

Try it online!

answered Aug 7, 2022 at 21:03
\$\endgroup\$
1
  • \$\begingroup\$ you can save 2 bytes by doing s#a instead of f s a: Try it online! it's shorter yet to use filter, but an answer using that already exists. \$\endgroup\$ Commented Aug 7, 2022 at 21:19
1
2

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.