Jewels and Stones

From Rosetta Code
Jewels and Stones is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Task

Create a function which takes two string parameters: 'stones' and 'jewels' and returns an integer.

Both strings can contain any number of upper or lower case letters. However, in the case of 'jewels', all letters must be distinct.

The function should count (and return) how many 'stones' are 'jewels' or, in other words, how many letters in 'stones' are also letters in 'jewels'.


Note that:

  1. Only letters in the ISO basic Latin alphabet i.e. 'A to Z' or 'a to z' need be considered.
  2. A lower case letter is considered to be different to its upper case equivalent for this purpose i.e. 'a' != 'A'.
  3. The parameters do not need to have exactly the same names.
  4. Validating the arguments is unnecessary.

So, for example, if passed "aAAbbbb" for 'stones' and "aA" for 'jewels', the function should return 3.

This task was inspired by this problem.

ALGOL 68[edit]

BEGIN
# procedure that counts the number of times the letters in jewels occur in stones #
PROC count jewels = ( STRING stones, jewels )INT:
BEGIN
# count the occurences of each letter in stones #
INT upper a pos = 0;
INT lower a pos = 1 + ( ABS "Z" - ABS "A" );
[ upper a pos : lower a pos + 26 ]INT letter counts;
FOR c FROM LWB letter counts TO UPB letter counts DO letter counts[ c ] := 0 OD;
FOR s pos FROM LWB stones TO UPB stones DO
CHAR s = stones[ s pos ];
IF s >= "A" AND s <= "Z" THEN letter counts[ upper a pos + ( ABS s - ABS "A" ) ] +:= 1
ELIF s >= "a" AND s <= "z" THEN letter counts[ lower a pos + ( ABS s - ABS "a" ) ] +:= 1
FI
OD;
# sum the counts of the letters that appear in jewels #
INT count := 0;
FOR j pos FROM LWB jewels TO UPB jewels DO
CHAR j = jewels[ j pos ];
IF j >= "A" AND j <= "Z" THEN count +:= letter counts[ upper a pos + ( ABS j - ABS "A" ) ]
ELIF j >= "a" AND j <= "z" THEN count +:= letter counts[ lower a pos + ( ABS j - ABS "a" ) ]
FI
OD;
count
END # count jewels # ;
 
print( ( count jewels( "aAAbbbb", "aA" ), newline ) );
print( ( count jewels( "[email protected]"
, "[email protected]"
)
, newline
)
);
print( ( count jewels( "AB", "" ), newline ) );
print( ( count jewels( "ZZ", "z" ), newline ) )
 
END
Output:
         +3
        +52
         +0
         +0

AppleScript[edit]

-- jewelCount :: String -> String -> Int
on jewelCount(jewels, stones)
set js to chars(jewels)
script
on |λ|(a, c)
if elem(c, jewels) then
a + 1
else
a
end if
end |λ|
end script
foldl(result, 0, chars(stones))
end jewelCount
 
-- OR in terms of filter
-- jewelCount :: String -> String -> Int
on jewelCount2(jewels, stones)
script
on |λ|(c)
elem(c, jewels)
end |λ|
end script
length of filter(result, stones)
end jewelCount2
 
-- TEST --------------------------------------------------
on run
 
unlines(map(uncurry(jewelCount), ¬
{Tuple("aA", "aAAbbbb"), Tuple("z", "ZZ")}))
 
end run
 
 
-- GENERIC FUNCTIONS -------------------------------------
 
-- Tuple (,) :: a -> b -> (a, b)
on Tuple(a, b)
{type:"Tuple", |1|:a, |2|:b}
end Tuple
 
-- chars :: String -> [Char]
on chars(s)
characters of s
end chars
 
-- elem :: Eq a => a -> [a] -> Bool
on elem(x, xs)
considering case
xs contains x
end considering
end elem
 
-- filter :: (a -> Bool) -> [a] -> [a]
on filter(f, xs)
tell mReturn(f)
set lst to {}
set lng to length of xs
repeat with i from 1 to lng
set v to item i of xs
if |λ|(v, i, xs) then set end of lst to v
end repeat
return lst
end tell
end filter
 
-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
repeat with i from 1 to lng
set v to |λ|(v, item i of xs, i, xs)
end repeat
return v
end tell
end foldl
 
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
 
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
 
-- Returns a function on a single tuple (containing 2 arguments)
-- derived from an equivalent function with 2 distinct arguments
-- uncurry :: (a -> b -> c) -> ((a, b) -> c)
on uncurry(f)
script
property mf : mReturn(f)'s |λ|
on |λ|(pair)
mf(|1| of pair, |2| of pair)
end |λ|
end script
end uncurry
 
-- unlines :: [String] -> String
on unlines(xs)
set {dlm, my text item delimiters} to ¬
{my text item delimiters, linefeed}
set str to xs as text
set my text item delimiters to dlm
str
end unlines
Output:
3
0

AWK[edit]

# syntax: GAWK -f JEWELS_AND_STONES.AWK
BEGIN {
printf("%d\n",count("aAAbbbb","aA"))
printf("%d\n",count("ZZ","z"))
exit(0)
}
function count(stone,jewel, i,total) {
for (i=1; i<length(stone); i++) {
if (jewel ~ substr(stone,i,1)) {
total++
}
}
return(total)
}
 
Output:
3
0

C[edit]

Translation of: Kotlin
#include <stdio.h>
#include <string.h>
 
int count_jewels(const char *s, const char *j) {
int count = 0;
for ( ; *s; ++s) if (strchr(j, *s)) ++count;
return count;
}
 
int main() {
printf("%d\n", count_jewels("aAAbbbb", "aA"));
printf("%d\n", count_jewels("ZZ", "z"));
return 0;
}
Output:
3
0

D[edit]

Translation of: Kotlin
import std.algorithm;
import std.stdio;
 
int countJewels(string s, string j) {
int count;
foreach (c; s) {
if (j.canFind(c)) {
count++;
}
}
return count;
}
 
void main() {
countJewels("aAAbbbb", "aA").writeln;
countJewels("ZZ", "z").writeln;
}
Output:
3
0

Factor[edit]

USING: kernel prettyprint sequences ;
: count-jewels ( stones jewels -- n ) [ member? ] curry count ;
 
"aAAbbbb" "aA"
"ZZ" "z" [ count-jewels . ] [email protected]
Output:
3
0

Go[edit]

Four solutions are shown here. The first of two simpler solutions iterates over the stone string in an outer loop and makes repeated searches into the jewel string, incrementing a count each time it finds a stone in the jewels. The second of the simpler solutions reverses that, iterating over the jewel string in the outer loop and accumulating counts of matching stones. This solution works because we are told that all letters of the jewel string must be unique. These two solutions are simple but are both O(|j|*|s|).

The two more complex solutions are analogous to the two simpler ones but build a set or multiset as preprocessing step, replacing the inner O(n) operation with an O(1) operation. The resulting complexity in each case is O(|j|+|s|).

Outer loop stones, index into jewels:

package main
 
import (
"fmt"
"strings"
)
 
func js(stones, jewels string) (n int) {
for _, b := range []byte(stones) {
if strings.IndexByte(jewels, b) >= 0 {
n++
}
}
return
}
 
func main() {
fmt.Println(js("aAAbbbb", "aA"))
}
Output:
3

Outer loop jewels, count stones:

func js(stones, jewels string) (n int) {
for _, b := range []byte(jewels) {
n += strings.Count(stones, string(b))
}
return
}

Construct jewel set, then loop over stones:

func js(stones, jewels string) (n int) {
var jSet ['z' + 1]int
for _, b := range []byte(jewels) {
jSet[b] = 1
}
for _, b := range []byte(stones) {
n += jSet[b]
}
return
}

Construct stone multiset, then loop over jewels:

func js(stones, jewels string) (n int) {
var sset ['z' + 1]int
for _, b := range []byte(stones) {
sset[b]++
}
for _, b := range []byte(jewels) {
n += sset[b]
}
return
}

Haskell[edit]

jewelCount :: String -> String -> Int 
jewelCount jewels =
foldr (\c -> if elem c jewels then succ else id) 0
 
 
-- TEST ----------------------------------------------
 
main :: IO ()
main = mapM_ print $
(uncurry jewelCount) <$> [
("aA", "aAAbbbb")
,("z", "ZZ")
]
Output:
3
0

Or in terms of filter rather than foldr

jewelCount :: String -> String -> Int 
jewelCount jewels =
length . filter (flip elem jewels)
 
-- Which could be further reduced to
-- jewelCount = (length .) . filter . flip elem
 
-- TEST ----------------------------------------------
 
main :: IO ()
main = do
print $ jewelCount "aA" "aAAbbbb"
print $ jewelCount "z" "ZZ"
Output:
3
0

JavaScript[edit]

(() => {
 
// jewelCount :: String -> String -> Int
const jewelCount = (j, s) => {
const js = j.split('');
return s.split('')
.reduce((a, c) => js.includes(c) ? a + 1 : a, 0)
};
 
// TEST -----------------------------------------------
return [
['aA', 'aAAbbbb'],
['z', 'ZZ']
]
.map(x => jewelCount(...x))
})();
Output:
[3, 0]

Julia[edit]

Module:

module Jewels
 
count(s, j) = Base.count(x ∈ j for x in s)
 
end # module Jewels

Main:

@show Jewels.count("aAAbbbb", "aA")
@show Jewels.count("ZZ", "z")
Output:
Jewels.count("aAAbbbb", "aA") = 3
Jewels.count("ZZ", "z") = 0

Kotlin[edit]

// Version 1.2.40
 
fun countJewels(s: String, j: String) = s.count { it in j }
 
fun main(args: Array<String>) {
println(countJewels("aAAbbbb", "aA"))
println(countJewels("ZZ", "z"))
}
Output:
3
0

Maple[edit]

count_jewel := proc(stones, jewels)
local count, j, letter:
j := convert(jewels,set):
count := 0:
for letter in stones do
if (member(letter, j)) then
count++:
end if:
end do:
return count:
end proc:
count_jewel("aAAbbbb", "aA")
Output:
3

Modula-2[edit]

This example does not show the output mentioned in the task description on this page (or a page linked to from here). Please ensure that it meets all task requirements and remove this message.
Note that phrases in task descriptions such as "print and display" and "print and show" for example, indicate that (reasonable length) output be a part of a language's solution.


MODULE Jewels;
FROM FormatString IMPORT FormatString;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;
 
PROCEDURE WriteInt(n : INTEGER);
VAR buf : ARRAY[0..15] OF CHAR;
BEGIN
FormatString("%i", buf, n);
WriteString(buf)
END WriteInt;
 
PROCEDURE CountJewels(s,j : ARRAY OF CHAR) : INTEGER;
VAR c,i,k : CARDINAL;
BEGIN
c :=0;
 
FOR i:=0 TO HIGH(s) DO
FOR k:=0 TO HIGH(j) DO
IF (j[k]#0C) AND (s[i]#0C) AND (j[k]=s[i]) THEN
INC(c);
BREAK
END
END
END;
 
RETURN c
END CountJewels;
 
BEGIN
WriteInt(CountJewels("aAAbbbb", "aA"));
WriteLn;
WriteInt(CountJewels("ZZ", "z"));
WriteLn;
 
ReadChar
END Jewels.

Perl 6[edit]

sub count-jewels ( Str $j, Str $s --> Int ) {
my %counts_of_all = $s.comb.Bag;
my @jewel_list = $j.comb.unique;
 
return %counts_of_all@jewel_list.Bag ?? %counts_of_all{ @jewel_list }.sum !! 0;
}
 
say count-jewels 'aA' , 'aAAbbbb';
say count-jewels 'z' , 'ZZ';
Output:
3
0

Python[edit]

def countJewels(s, j):
return sum(x in j for x in s)
 
print countJewels("aAAbbbb", "aA")
print countJewels("ZZ", "z")
Output:
3
0

Python 3 Alternative[edit]

def countJewels(stones, jewels):
jewelset = set(jewels)
return sum(1 for stone in stones if stone in jewelset)
 
print(countJewels("aAAbbbb", "aA"))
print(countJewels("ZZ", "z"))
Output:
3
0

Racket[edit]

#lang racket
 
(define (jewels-and-stones stones jewels)
(length (filter (curryr member (string->list jewels)) (string->list stones))))
 
(module+ main
(jewels-and-stones "aAAbbbb" "aA")
(jewels-and-stones "ZZ" "z"))
 
Output:
3
0

REXX[edit]

Programming note:   a check is made so that only (Latin) letters are counted as a match.

/*REXX pgm counts how many letters (in the 1st string) are in common with the 2nd string*/
say count('aAAbbbb', "aA")
say count('ZZ' , "z" )
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
count: procedure; parse arg stones,jewels /*obtain the two strings specified. */
#=0 /*initalize the variable # to zero. */
do j=1 for length(stones) /*scan STONES for matching JEWELS chars*/
x=substr(stones, j, 1) /*obtain a character of the STONES var.*/
if datatype(x, 'M') then if pos(x, jewels)\==0 then #=# + 1
end /*j*/ /*if a letter & a match, bump # counter*/
return # /*return the number of common letters. */
output   when using the default inputs:
3
0

Ring[edit]

# Project  Jewels and Stones
# Date 2018/04/25
# Author Gal Zsolt (~ CalmoSoft ~)
# Email <[email protected]>
 
jewels = "aA"
stones = "aAAbbbb"
see jewelsandstones(jewels,stones) + nl
jewels = "z"
stones = "ZZ"
see jewelsandstones(jewels,stones) + nl
 
func jewelsandstones(jewels,stones)
num = 0
for n = 1 to len(stones)
pos = substr(jewels,stones[n])
if pos > 0
num = num + 1
ok
next
return num
 

Output:

3
0

Scala[edit]

object JewelsStones extends App {
def countJewels(s: String, j: String): Int = s.count(i => j.contains(i))
 
println(countJewels("aAAbbbb", "aA"))
println(countJewels("ZZ", "z"))
}
Output:
See it in running in your browser by ScalaFiddle (JavaScript) or by Scastie (JVM).

Sidef[edit]

func countJewels(s, j) {
s.chars.count { |c|
j.contains(c)
}
}
 
say countJewels("aAAbbbb", "aA") #=> 3
say countJewels("ZZ", "z") #=> 0

zkl[edit]

fcn countJewels(a,b){ a.inCommon(b).len() }
println(countJewels("aAAbbbb", "aA"));
println(countJewels("ZZ", "z"));
Output:
3
0