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 code-golf, so shortest code wins!
47 Answers 47
Rust, 20 bytes
str::matches::<&[_]>
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
.
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;$_}
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,''}
PowerShell, 42 bytes
$args-join'␀'-creplace'(?s)(.)(?!.*␀.*1円)'
Takes the two strings as arguments.
JavaScript (ES9), 43 bytes
a=>a.join`␀`.replace(/(.)(?!.*␀.*1円)/sg,'')
Takes a list containing the two strings.
Java, 52 bytes
s->a->(s+"␀"+a).replaceAll("(?s)(.)(?!.*␀.*\1円)","")
\$\large\textit{Full programs}\$
Perl, 37 bytes
$_=join'',<>;s/(.)(?!.*␀.*1円)//sg;say
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.
R, 15 bytes
\(s,a)s[s%in%a]
Takes input and outputs through vectors of character codes (as in linked test suite) or vectors of characters.
Brachylog, 4 bytes
dt∋v
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.
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++));}
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.
-
-
\$\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 anint
\$\endgroup\$c--– c--2022年08月19日 14:30:42 +00:00Commented Aug 19, 2022 at 14:30 -
\$\begingroup\$ You can change it to
f(*s,*a)(...
if you really want to. \$\endgroup\$jdt– jdt2022年08月19日 14:37:22 +00:00Commented Aug 19, 2022 at 14:37
Pip, 5 bytes
a@X^b
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.
Python, (削除) 35 (削除ここまで) 28 bytes
lambda a,b:filter(b.count,a)
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
-
5\$\begingroup\$ 28 bytes \$\endgroup\$dingledooper– dingledooper2022年08月07日 21:32:59 +00:00Commented Aug 7, 2022 at 21:32
-
\$\begingroup\$ Don't think it works, @dingledooper: ATOL. Think that list comprehension was right, tho. \$\endgroup\$dsillman2000– dsillman20002022年08月14日 00:52:56 +00:00Commented 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\$dsillman2000– dsillman20002022年08月14日 01:06:15 +00:00Commented 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\$dingledooper– dingledooper2022年08月14日 01:12:01 +00:00Commented Aug 14, 2022 at 1:12
sh + coreutils, 6 bytes
tr -cd
Takes string s
from stdin
, alphabet a
as an argument.
-
\$\begingroup\$ Incomplete code snippet. An actually useful function using
tr
is at least 14 bytes. Attempt this online! \$\endgroup\$roblogic– roblogic2022年12月25日 10:31:13 +00:00Commented 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
fromstdin
,a
as a third argument). \$\endgroup\$matteo_c– matteo_c2022年12月25日 10:39:28 +00:00Commented Dec 25, 2022 at 10:39 -
1\$\begingroup\$ @roblogic see codegolf.meta.stackexchange.com/a/5415/73593 \$\endgroup\$matteo_c– matteo_c2022年12月25日 10:44:39 +00:00Commented Dec 25, 2022 at 10:44
BQN, 3 bytes
∊/⊣
/ # Replicate elements of
⊣ # left argument
# by
∊ # 1 if each element of left argument is in right argument
# 0 otherwise
JavaScript (Node.js), 44 bytes
s=>a=>[...s].filter(c=>a.includes(c)).join``
Unfortunately, using .filter(a.includes)
for 38 (wow!) throws String.prototype.includes called on null or undefined
-
1\$\begingroup\$ The output from that test harness is a bit hard to read, so for convenience: Try it online! \$\endgroup\$Deadcode– Deadcode2022年08月08日 19:38:36 +00:00Commented 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\$Deadcode– Deadcode2022年08月08日 19:41:34 +00:00Commented Aug 8, 2022 at 19:41
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
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
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.
-
\$\begingroup\$ 30 bytes or 5 bytes? \$\endgroup\$Dominic van Essen– Dominic van Essen2022年08月09日 11:26:28 +00:00Commented 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\$Neil– Neil2022年08月09日 11:44:25 +00:00Commented Aug 9, 2022 at 11:44
Raku, 22 bytes
{$^a.trans($^b=>""):c}
trans
is Raku's beefed-up version of Perl 5's transliteration operator tr
.
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,""),"")}
-
2\$\begingroup\$
tr
parsesa
like a regex character class; ranges (e.g.a-z
) are parsed, and^
at the beginning negates. So this answer is incorrect unlessa
can be quoted/escaped in such a way that no characters are treated specially. \$\endgroup\$Deadcode– Deadcode2022年08月13日 20:40:16 +00:00Commented Aug 13, 2022 at 20:40 -
\$\begingroup\$ Welcome to Code Golf! \$\endgroup\$2022年08月13日 22:29:42 +00:00Commented Aug 13, 2022 at 22:29
-
\$\begingroup\$ Nice. This can be shortened further, to 25 bytes: Attempt This Online! \$\endgroup\$Deadcode– Deadcode2022年08月13日 23:44:06 +00:00Commented Aug 13, 2022 at 23:44
-
\$\begingroup\$ Also, 27 byte version that works on the older Ruby version on TIO: Try it online! \$\endgroup\$Deadcode– Deadcode2022年08月13日 23:49:20 +00:00Commented Aug 13, 2022 at 23:49
Haskell, 20 bytes
a#b=filter(`elem`b)a
Rust, 70 bytes
|a:&str,b:&[u8]|a.bytes().filter(|d|b.contains(d)).collect::<Vec<_>>()
-
\$\begingroup\$ You didn't edit this into the list of answers. \$\endgroup\$Aiden Chow– Aiden Chow2022年08月08日 20:54:56 +00:00Commented Aug 8, 2022 at 20:54
Wolfram Language (Mathematica), 16 bytes
Cases[#|##&@@#]&
Input and output two lists of characters [alphabet][string]
.
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.
-
1\$\begingroup\$ You don't need to count
f=
(an anonymous function is valid) or the final linefeed: tio.run/##y08uSSxL/… \$\endgroup\$Luis Mendo– Luis Mendo2022年08月08日 21:37:27 +00:00Commented Aug 8, 2022 at 21:37
-
\$\begingroup\$ you can save 2 bytes by doing
s#a
instead off s a
: Try it online! it's shorter yet to usefilter
, but an answer using that already exists. \$\endgroup\$naffetS– naffetS2022年08月07日 21:19:58 +00:00Commented Aug 7, 2022 at 21:19
intersection/3
\$\endgroup\$