Write a program or function that takes in a string and outputs a count of each modern English alphabet letter in the string, case-insensitive.
Input: A string consisting of printable ASCII characters (code points 32-126).
Output: A list of pairs, where each pair consists of a letter and its count in the string. The list should be sorted in alphabetical order by letter. The list shall omit letters occurring zero times.
Test Cases
Input: "hello world"
Output: [('d', 1), ('e', 1), ('h', 1), ('l', 3), ('o', 2), ('r', 1), ('w', 1)]
Input: "The quick brown fox jumps over the lazy dog"
Output: [('a', 1), ('b', 1), ('c', 1), ('d', 1), ('e', 3), ('f', 1), ('g', 1), ('h', 2), ('i', 1), ('j', 1), ('k', 1), ('l', 1), ('m', 1), ('n', 1), ('o', 4), ('p', 1), ('q', 1), ('r', 2), ('s', 1), ('t', 2), ('u', 2), ('v', 1), ('w', 1), ('x', 1), ('y', 1), ('z', 1)]
Code Golf Specifics:
Your goal is to write the shortest possible code in bytes that correctly solves the problem. Your code must be able to handle any valid input within the given constraints. Note that your code should treat uppercase and lowercase letters as equivalent.
Good luck!
47 Answers 47
Python, 60 bytes
lambda s:{c:s.lower().count(c)for c in s.lower()if'`'<c<'{'}
Returns a dictionary. Suggested by @JonathanAllan.
Python, 70 bytes
lambda s:sorted((c,s.lower().count(c))for c in{*s.lower()}if'`'<c<'{')
Returns a sorted list of tuples.
Python, 75 bytes
lambda s:sorted({*zip(x:=[*filter(str.isalpha,s.lower())],map(x.count,x))})
Returns a sorted list of tuples.
Commented
lambda s: sorted( # Define an anonymous function which takes a string, s,
# and returns a sorted version of the following:
(c, s.lower().count(c)) # a tuple of the character, c, and its count
# in the lowercase version of s
for c in {*s.lower()} # for each character, c, in the lowercase version of s uniquified
if '`' < c < '{' ) # but only keep it if it is between the characters
# '`' (right before 'a') and '{' (right after 'z')
# i.e., it's alphabetic
lambda s: sorted( # Define an anonymous function which takes a string, s,
# and returns a sorted version of the following:
{*zip( # a uniquified version of two iterables zipped together:
x := [*filter( # filter by
str.isalpha, # is the character in the alphabet
s.lower() # apply to a lowercase version of s
)], # and store in x
map(x.count, x) )}) # the counts of each character in x
-
\$\begingroup\$ OP appears to allow a dictionary as output in the comments, which would make this only \60ドル\$ with
lambda s:{c:s.lower().count(c)for c in s.lower()if'`'<c<'{'}. \$\endgroup\$Jonathan Allan– Jonathan Allan2023年03月04日 18:29:35 +00:00Commented Mar 4, 2023 at 18:29 -
\$\begingroup\$ @JonathanAllan that wouldn't be sorted though, would it? Adding the sort would be 76 bytes \$\endgroup\$The Thonnu– The Thonnu2023年03月04日 20:08:03 +00:00Commented Mar 4, 2023 at 20:08
-
\$\begingroup\$ No, it wouldn't be sorted, but if they allow what was linked to then a plain dictionary is acceptable. \$\endgroup\$Jonathan Allan– Jonathan Allan2023年03月04日 22:23:17 +00:00Commented Mar 4, 2023 at 22:23
-
\$\begingroup\$ @JonathanAllan alright, thanks. \$\endgroup\$The Thonnu– The Thonnu2023年03月05日 10:03:50 +00:00Commented Mar 5, 2023 at 10:03
C (gcc), (削除) 97 (削除ここまで) (削除) 94 (削除ここまで) 87 bytes
- -3 thanks to Unrelated String
- -7 thanks to c--
Uses uppercase as the challenge only states case-insensitive.
f(char*s){for(int a[96]={},i=64;i<90;)*s?a[*s++&95]++:a[++i]&&printf("%c:%d ",i,a[i]);}
Ungolfed:
f(char*s){
for(int a[96]={},i=64;
i<90;) // for all characters in string, then from 'A' to 'Z':
*s? // done processing string?
a[*s++&95]++: // no, uppercase letter and increment count
a[++i]&&printf("%c:%d ",i,a[i]); // yes, print counts
}
-
\$\begingroup\$ If uppercase is allowed, 95 \$\endgroup\$Unrelated String– Unrelated String2023年03月05日 05:23:56 +00:00Commented Mar 5, 2023 at 5:23
jq, 66 bytes
ascii_downcase|reduce match("[a-z]";"g").string as $c({};.[$c]+=1)
reduce is just too good.
Java (JDK), (削除) 151 (削除ここまで) (削除) 142 (削除ここまで) 135 bytes
s->{var m=new java.util.TreeMap();for(var c:s.replaceAll("[^a-zA-Z]","").toCharArray())m.merge(c|=32,1,(a,b)->(int)a+(int)b);return m;}
Saved 15 bytes thanks to Kevin Cruijssen.
-
1\$\begingroup\$ You can remove
<Character,Long>and use1,(a,b)->(int)a+(int)binstead for -7 bytes. And you can also changed the.chars().forEach(c->with(char)cto a regularfor(var c:s....toCharArray())andcfor another -2 bytes: try it online. \$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2023年03月04日 15:32:48 +00:00Commented Mar 4, 2023 at 15:32 -
1\$\begingroup\$ Oh, and -6 more bytes by using
c|=32instead ofc, adding the case-insensitive flag(?i)to the regex, and removing the.toLowerCase(): try it online. :) (Relevant tip.) \$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2023年03月04日 15:38:39 +00:00Commented Mar 4, 2023 at 15:38 -
1\$\begingroup\$ @KevinCruijssen Nice, I'd forgotten about those bitwise tricks with ASCII. Actually it seems
[^a-zA-Z]is shorter than(?i)[^a-z]though. \$\endgroup\$Unmitigated– Unmitigated2023年03月04日 15:40:14 +00:00Commented Mar 4, 2023 at 15:40
Excel, (削除) 85 (削除ここまで) 82 bytes
Saved 3 bytes thanks to JvdV
=LET(c,CHAR(ROW(65:90)),q,LEN(A1)-LEN(SUBSTITUTE(UPPER(A1),c,)),FILTER(c&"="&q,q))
The LET() function allows you to assign variables to values and reference them by name later. Every term is a pair except the last which is the output.
c,CHAR(ROW(65:90))creates an array of the stringsAthroughZ.q,LEN(a)-LEN(SUBSTITUTE(UPPER(a),c,))creates an array of how many times each letter appears by measuring the length of the input vs. the length if we replace that letter with nothing.SUBSTITUTE()is case-sensitive so we transform the input to uppercase.FILTER(c&"="&q,q)combines the array of letters with the count of each character and then filter for just those where the count (q) was truthy (anything not zero).
-
1\$\begingroup\$ If OP doesn't require tupples and uppercase answers are allowed, then maybe remove the 1st variable and nest it inside
SUBSTITUTE():=LET(x,CHAR(ROW(65:90)),y,LEN(A1)-LEN(SUBSTITUTE(UPPER(A1),x,)),FILTER(x&"="&y,y))for 82 bytes. \$\endgroup\$JvdV– JvdV2023年03月07日 12:27:04 +00:00Commented Mar 7, 2023 at 12:27 -
1\$\begingroup\$ @JvdV Good point. I usually write
LET()functions for PPCG in their long form and then cut it down. I overlooked the fact thatLEN()doesn't care about case so I wasn't saving bytes*2 with the variable. \$\endgroup\$Engineer Toast– Engineer Toast2023年03月07日 14:37:28 +00:00Commented Mar 7, 2023 at 14:37
PowerShell Core, 62 bytes
$args-match'[a-z]'|%{"$_"|% *l*r}|group|%{,($_.Name,$_.Count)}
$args-match'[a-z]' # For each character argument, exclude non letters characters
|%{"$_"|% *l*r} # Converts to lowercase
|group # Groups them
|%{,($_.Name,$_.Count)} # build pairs of letters and counts
-
\$\begingroup\$ Love the solution, but it's missing a sort, unfortunately. \$\endgroup\$Bruno Brant– Bruno Brant2023年03月08日 04:04:40 +00:00Commented Mar 8, 2023 at 4:04
-
\$\begingroup\$ @BrunoBrant The output seems sorted by characters already, it looks like
groupdoes it by default. Do you have a failing test case that I could try? \$\endgroup\$Julian– Julian2023年03月08日 18:58:00 +00:00Commented Mar 8, 2023 at 18:58
Pascal (FPC), (削除) 185 (削除ここまで) ... 134 bytes
var c,d:char;s:string;i:word;begin;read(s);for c:=^to^do begin;i:=0;for d in upcase(s)do i+=ord(c=d);if i>0then writeln(c,i)end;end.
Try it online! (134b, courtesy of @michael-tkach)
(削除) 150b (削除ここまで)
(削除) 155b (削除ここまで)
(削除) 160b (削除ここまで)
(削除) 161b (削除ここまで)
(削除) 162b (削除ここまで)
(削除) 185b (削除ここまで)
Iterates over the alphabet and the input string s, comparing chars d and c. The for <char> in <string> syntax was handy. Implemented some of the Pascal golfing tips.
-
1\$\begingroup\$ You may get 134 with those little tricks... tio.run/##JY1BDsIgEEXjNVzNssRqumaCR2mCM9MyCYEG0B4fiS7@6r28f/… \$\endgroup\$michael-tkach– michael-tkach2023年04月24日 14:11:42 +00:00Commented Apr 24, 2023 at 14:11
Mathematica (Wolfram Language), 34 bytes
KeySort@*LetterCounts@*ToLowerCase
TIO.run is in the comments below. Edited to save 4 bytes thanks to a suggestion from ZaMoC.
-
1
-
\$\begingroup\$ I just got it to work on TIO, but your answer is shorter. Thanks. \$\endgroup\$dirvine– dirvine2023年03月03日 21:05:12 +00:00Commented Mar 3, 2023 at 21:05
-
1\$\begingroup\$ Hi, in order to avoid [] you can also use KeySort@LetterCounts@ToLowerCase@#& for 35 bytes. But in this case you can "chain" 3 functions using @* for 1 extra byte. \$\endgroup\$ZaMoC– ZaMoC2023年03月03日 21:10:57 +00:00Commented Mar 3, 2023 at 21:10
-
\$\begingroup\$ Yeah, I should have thought about the operator form. Thanks for your suggestion. I did that on my answer to this related question: codegolf.stackexchange.com/questions/258558/… \$\endgroup\$dirvine– dirvine2023年03月03日 21:13:04 +00:00Commented Mar 3, 2023 at 21:13
-
\$\begingroup\$ It's strange that LetterCounts works fine on tio.run, but WordCounts causes an error. (WordCounts is used in the answer to the question in the previous comment.) I guess WordCounts uses some NLP, but that isn't needed for just counting letters. \$\endgroup\$dirvine– dirvine2023年03月03日 21:17:41 +00:00Commented Mar 3, 2023 at 21:17
JavaScript (ES6), 82 bytes
Probably takes a list of pairs a bit too literally... ̄\_(ツ)_/ ̄
s=>[...s.toLowerCase()].sort().join``.match(/([a-z])1円*/g).map(s=>[s[0],s.length])
-
\$\begingroup\$
s.split(c)is not right. You take into account the case of letters when separating. Because of this forThe tuick brown fox jumps over the lazy dogyour function outputs only2 tinstead of3 t\$\endgroup\$EzioMercer– EzioMercer2023年03月04日 04:15:17 +00:00Commented Mar 4, 2023 at 4:15 -
\$\begingroup\$ @EzioMercer You're right. Updated to a new method. \$\endgroup\$Arnauld– Arnauld2023年03月04日 08:55:13 +00:00Commented Mar 4, 2023 at 8:55
-
-
\$\begingroup\$ @Shaggy I decided to return a list and there's already an answer using an object, so I'll stick to that. \$\endgroup\$Arnauld– Arnauld2023年03月04日 15:20:24 +00:00Commented Mar 4, 2023 at 15:20
JavaScript, 68 bytes
s=>s.toLowerCase(m={}).match(/[a-z]/g).sort().map(l=>m[l]=-~m[l])&&m
Try it:
f=s=>s.toLowerCase(m={}).match(/[a-z]/g).sort().map(l=>m[l]=-~m[l])&&m
;[
'hello world',
'The tuick brown fox jumps over the lazy dog'
].forEach(s=>console.log(f(s)))
UPD 73 -> 68
Thanks to Shaggy for the tips (one, two) to reduce bytes count
-
4\$\begingroup\$
(m[l]||0)+1can be-~m[l]\$\endgroup\$Shaggy– Shaggy2023年03月04日 07:51:19 +00:00Commented Mar 4, 2023 at 7:51 -
4\$\begingroup\$ Oh, and you can initialise
mwithintoLowerCase()to save another byte. \$\endgroup\$Shaggy– Shaggy2023年03月04日 08:07:27 +00:00Commented Mar 4, 2023 at 8:07 -
1\$\begingroup\$ Actually, assigning the RegEx to
mrather than using an explicit object should work, too. \$\endgroup\$Shaggy– Shaggy2023年03月04日 13:09:37 +00:00Commented Mar 4, 2023 at 13:09 -
\$\begingroup\$ @Shaggy You mean
m=/[a-z]/g? \$\endgroup\$EzioMercer– EzioMercer2023年03月04日 13:23:19 +00:00Commented Mar 4, 2023 at 13:23
05AB1E, (削除) 9 (削除ここまで) 6 bytes
álТøê
Input as a list of characters.
Alternative 6 bytes answer with input as a string: (suggested by @KevinCruijssen)
ál{Åγø
-3 thanks to @KevinCruijssen
Explanation
á # Filter for alphabetic characters only
lÐ # Convert to lowercase and triplicate
¢ # Count the occurences of each character
øê # Zip, sort, and uniquify
á # Filter for alphabetic characters only
l{ # Convert to lowercase and sort
Åγ # Run-length encode the string
ø # Zip
-
\$\begingroup\$
ʒa}is the builtiná. :) Also, you can remove theSby taking the input as a list of characters: try it online. Or if you prefer to keep the input as string, here is a 6 bytes alternative using the run-length encode builtin:ál{Åγø\$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2023年03月04日 15:24:56 +00:00Commented Mar 4, 2023 at 15:24 -
\$\begingroup\$ @KevinCruijssen thanks, updated! \$\endgroup\$The Thonnu– The Thonnu2023年03月04日 15:36:01 +00:00Commented Mar 4, 2023 at 15:36
-
1\$\begingroup\$ No need to use outer splat.
->s{s.upcase.chars.tally.slice(*?A..?Z).sort}works just fine. \$\endgroup\$radarek– radarek2023年05月16日 09:09:13 +00:00Commented May 16, 2023 at 9:09
Retina 0.8.2, (削除) 38 (削除ここまで) 29 bytes
T`Llp`ll_
O`.
(.)1円*
1,ドル $.&¶
Try it online! Output includes trailing newlines. Saved 9 bytes thank to @FryAmTheEggman. Explanation:
T`Llp`ll_
Convert letters to lower case and delete all other printable ASCII.
O`.
Sort the characters.
(.)1円*
1,ドル $.&¶
Output the count of each letter.
Previous 38-byte version worked with any input, not just printable ASCII:
T`L`l
O`.
M!`([a-z])1円*
(.)1円*
1,ドル $.&
Try it online! Explanation:
T`L`l
Lowercase the input string.
O`.
Sort the characters.
M!`([a-z])1円*
Extract the runs of identical letters.
(.)1円*
1,ドル $.&
Output the count of each letter.
(削除) 31 (削除ここまで) 30 bytes in Retina 1:
.
$L
O`.
L$`([a-z])1円*
1,ドル $.&
Try it online! Explanation:
.
$L
Lowercase the input.
O`.
Sort the characters.
L$`([a-z])1円*
For each run of identical letters...
1,ドル $.&
... output the count of each letter.
-
\$\begingroup\$ It seems you can save a bit by removing the bad characters instead of keeping the good ones. \$\endgroup\$FryAmTheEggman– FryAmTheEggman2023年03月07日 04:23:20 +00:00Commented Mar 7, 2023 at 4:23
-
\$\begingroup\$ Perhaps a few more by using
Tmore. \$\endgroup\$FryAmTheEggman– FryAmTheEggman2023年03月07日 04:25:54 +00:00Commented Mar 7, 2023 at 4:25
Pip, (削除) 21 (削除ここまで) 23 bytes
YSSLCaFiUQy@XL;Pi.(iNy)
How?
YSSLCaFiUQy@XL;Pi.(iNy) : One arg; str
a : First input
LC : To lowercase
SS : Sort
Y : Yank
Fi : For i in
UQy : Unique values of y
@XL : Only lowercase alphabet characters
P : Print
i : Letter
. : Concatenated with
iN : Letter in
y : Input
-
\$\begingroup\$ This works on the current test cases, but the challenge specifies that all non-letter characters should be ignored, not just spaces. I think looping over
zand adding some logic to skip letters whose count is zero will be your best bet. \$\endgroup\$DLosc– DLosc2023年03月16日 18:23:18 +00:00Commented Mar 16, 2023 at 18:23 -
\$\begingroup\$ @DLosc Sorry about that! This should work? Lmk if there're any more problems :) \$\endgroup\$Baby_Boy– Baby_Boy2023年03月16日 19:38:20 +00:00Commented Mar 16, 2023 at 19:38
Charcoal, 15 bytes
⭆1ΦEβ⟦λNo↧θλ⟧§λ1
Try it online! Link is to verbose version of code. Explanation:
β Predefined variable lowercase alphabet
E Map over letters
λ Current letter
⟦ ⟧ Make into tuple with
No Count of
λ Current letter in
θ Input string
↧ Lowercased
Φ Filtered where
§λ1 Count was nonzero
⭆1 Pretty-print
J9.4, 35 bytes
'\pL'(~.,:<@#/.~)@/:~@rxall tolower
J903, 37 bytes
'[a-z]'(~.,:<@#/.~)@/:~@rxall tolower
Explanation is the same, but the PCRE engine was updated which makes the regex 2 bytes shorter.
'\pL'(~.,:<@#/.~)@/:~@rxall tolower
tolower NB. lowercase the input
'\pL' rxall NB. match every letter
/:~@ NB. then sort
( )@ NB. then invoke a monadic fork
#/.~ NB. count the occurrences of each letter
<@ NB. then box each result
~. NB. uniquify the matches
,: NB. stack matches on top of counts
Thunno, \18ドル\log_{256}(96)\approx\$ 14.82 bytes
UgAzsAqkztcsZZZUz:
Explanation
U # Lowercase
gAzsAqk # Alphabetic characters only
zt # Triplicate
cs # Counts of each
ZZ # Zip
ZU # Uniquify
z: # Sort
J, 32 bytes
(u:97+i.26)(e.#[;"+1#.=/)tolower
u:97+i.26 A character vector of all lowercase letters.
tolower Input converted to lowercase.
(u:97+i.26)(...)tolower Apply inner function with lowercase alphabet as left argument and lowercased string as right argument.
=/ Equality table.
1#. Sum each row. This gives a vector of length 26 with the count of each letter in the input.
[;"+ Pair up each letter with its count.
e.# Only keep the pairs where the letter is an element of the input.
Jelly, 8 bytes
ŒlḟŒuṢŒr
At least slightly less boring than if I'd used Øa. Feels ever so vaguely beatable, still...
Œl The lowercased input,
ḟŒu with elements of the uppercased input filtered out.
ṢŒr Sort and run-length encode.
Japt v2.0a0, (削除) 15 (削除ここまで) 13 bytes
v r\L ü ËÎ+DÊ
-2 by Shaggy
Outputs a list of "ab" strings where a is the character and b is the number of occurrences
Japt, 7 bytes
ü ËÎ+DÊ
Doesn’t remove non-letters
Made on My iPhone
ü ËÎ+DÊ # input string
ü # list of same characters grouped together
Ë # map each string of same char to:
Î # the character
+DÊ # append length of group
-
\$\begingroup\$ Note that the challenge requires the counting of letters only and that the output be sorted by character. \$\endgroup\$Shaggy– Shaggy2023年03月06日 10:14:02 +00:00Commented Mar 6, 2023 at 10:14
-
\$\begingroup\$ @Shaggy Oops, forgot to read the rules lol \$\endgroup\$noodle person– noodle person2023年03月06日 12:07:00 +00:00Commented Mar 6, 2023 at 12:07
-
1
-
\$\begingroup\$ @Shaggy Only took you 20 seconds to golf mine! Thanks \$\endgroup\$noodle person– noodle person2023年03月06日 12:36:58 +00:00Commented Mar 6, 2023 at 12:36
-
\$\begingroup\$ You might be able to pass the
vas an argument toüinstead to save a byte but we'll need clarification on whether the output must be lowercase or if it can be mixed case. \$\endgroup\$Shaggy– Shaggy2023年03月06日 12:44:43 +00:00Commented Mar 6, 2023 at 12:44
Common Lisp, 110 bytes
(lambda(s)(reduce(lambda(s c &aux(e(assoc c s)))(if e(prog1 s(incf(cdr e)))(acons c 1 s)))s :initial-value()))
The ungolfed version is:
(defun frequencies (string)
(reduce (lambda (map char)
(let ((entry (assoc char map)))
(if entry
(prog1 map
(incf (cdr entry)))
(acons char 1 map))))
string
:initial-value nil))
For example:
> (frequencies "abcbad")
((#\d . 1) (#\c . 1) (#\b . 2) (#\a . 2))
Pascal, (削除) 590 (削除ここまで) 358 bytes
This full program requires a processor supporting features of ISO standard 10206 "Extended Pascal".
Furthermore,
- the implementation-dependent behavior of the selection order in a
for ... inset member iteration statement must be ascending, - the implementation-defined default
TotalWidthforinteger-typewritearguments must be sufficiently large in order to leave some space between a character and the number, and - the implementation-defined set of available characters contains both upper and lowercase characters.
The GPC (GNU Pascal Compiler) fulfills these conditions on an x86‐64 Linux system if compiling with the ‐‐extended-pascal option.
program p(input,output);var c:char;f:array[char]of integer value[otherwise 0];begin while not EOF do begin read(c);c:=(c+'ABCDEFGHIJKLMNOPQRSTUVWXYZ')[index('abcdefghijklmnopqrstuvwxyz',c)+1];f[c]:=f[c]+1 end;for c in['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']do if 0<f[c]then writeLn(c,f[c])end.
Ungolfed:
program letterFrequency(input, output);
var
c: char;
letterFrequency: array[char] of integer value [otherwise 0];
begin
while not EOF(input) do
begin
{ `read(input, c)` is equivalent to `c := input^; get(input)`. }
read(input, c);
{ There is no built-in "change case" function as Pascal does not
guarantee the coexistence of lower and uppercase letters. The EP
function `index(source, pattern)` returns the index of the first
occurence of `pattern` in `source`. If `pattern` is not found,
zero is returned. Remember, `string` indices are 1-based, thus
add `1` to select the prepended value of `c`. }
c := (c + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
[index('abcdefghijklmnopqrstuvwxyz', c) + 1];
letterFrequency[c] := letterFrequency[c] + 1;
end;
for c in ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] do
begin
if letterFrequency[c] > 0 then
begin
writeLn(c, letterFrequency[c]);
end;
end;
end.
See also FreePascal implementation.
-
1\$\begingroup\$ "Pascal does not guarantee that the characters 'a' through 'z' are arranged in contiguous order." — Ok, Pascal does not, but what about you?
q:=Pos(c,'abcdefghijklmnopqrstuvwxyz');if q>0then c:='ABCDEFGHIJKLMNOPQRSTUVWXYZ'[q];\$\endgroup\$manatwork– manatwork2023年03月06日 04:18:38 +00:00Commented Mar 6, 2023 at 4:18 -
\$\begingroup\$ @manAtWork Thanks for essentially reminding me of this golfing tip. I have adapted it to Extended Pascal, that means using the standardized
index. \$\endgroup\$Kai Burghardt– Kai Burghardt2023年03月06日 18:36:21 +00:00Commented Mar 6, 2023 at 18:36
CJam, 19 bytes
el_'{,97>--$e`{W%}%
Returns strings in the form of {char}{count}
Explanation
el_'{,97>--$e`{W%}% # a function taking an input string
el_ -- # remove all elements of the input which do not occur in
'{,97> # the character range lowercase a-z
$ # sort
e` # run-length encode (1h1e2l as an example)
{W%}% # to meet the output specification of {char}{count} and not {count}{char}
# we reverse each of the arrays in this sorted array
And any other shell that supports ${var,,} to downcase.
Bash, 35 bytes
grep -o [a-z]<<<${*,,}|sort|uniq -c
Haskell, (削除) 75 (削除ここまで) 71 bytes
-4 bytes thanks to Lynn
f s=[(l,n)|(u,l)<-zip['A'..'Z']['a'..],n<-[sum[1|c<-s,l==c||u==c]],n>0]
Explanation
List comprehensions seem to be shorter than map and filter.
f s=
Define our function, f, which takes a string s.
zip['A'..'Z']['a'..]
Create a list of (uppercase letter, lowercase letter) tuples.
(u,l)<-___
For each uppercase letter u and lowercase letter l in that list...
,n<-sum[1|c<-s,l==c||u==c]
Let n be the number of characters c in s for which c equals one of l and u...
[(l,n)|____,n>0]
Return a list of tuples of l and the corresponding n where n is greater than 0.
A solution using toLower from Data.Char comes in at 76 bytes:
import Data.Char
f s=[(l,n)|l<-['a'..'z'],n<-[sum[1|c<-s,l==toLower c]],n>0]
-
1\$\begingroup\$ Slightly shorter is
f s=[(l,n)|(u,l)<-zip['A'..'Z']['a'..],n<-[sum[1|c<-s,c==u||c==l]],n>0]\$\endgroup\$lynn– lynn2023年05月12日 14:33:34 +00:00Commented May 12, 2023 at 14:33
Julia 1.0, 51 bytes
~s=(x='A':'Z';[email protected](in(x=>x+32),s);(x.=>y)[y.>0])
- Thanks to MarcMush for the following:
- replace
sum(==(x),uppercase(s))withsum(in(x=>x+32),s) - replace Tuples with Pairs (e.g.,
(a,b)vs.a=>b).
- replace
54 byte solution
~s=(y='A':'Z'.|>x->x=>sum(in(x=>x+32),s))[@.last(y)>0]
55 byte solution
~s=[x=>y for x='A':'Z' for y=sum(in(x=>x+32),s) if y>0]
- Thanks to Kirill L. for suggesting comprehensions and generator expressions!
-
1\$\begingroup\$ Thanks! Actually, I was including the assignment in the header, since I've seen other examples of that. I've now moved it to back to the code and updated the byte count. \$\endgroup\$Ashlin Harris– Ashlin Harris2023年03月27日 13:43:06 +00:00Commented Mar 27, 2023 at 13:43
-
1\$\begingroup\$ This would be fine, since it is an anonymous function, and the header is just to store it, but what you did was a snippet, not a function (not valid Julia code by itself). If other answers are not valid, I try to point it out (not many people check Julia answers) \$\endgroup\$MarcMush– MarcMush2023年03月28日 15:43:38 +00:00Commented Mar 28, 2023 at 15:43
-
1
-
1\$\begingroup\$ -6 bytes by avoiding the way too long
uppercaseand using Pairs instead of Tuples Try it online! \$\endgroup\$MarcMush– MarcMush2023年05月18日 19:07:43 +00:00Commented May 18, 2023 at 19:07 -
1\$\begingroup\$ @MarcMush Brilliant! I can improve several of my other posts with those suggestions. I used your ideas to trim 11 bytes off my 62 byte solution, so now it's the best so far. \$\endgroup\$Ashlin Harris– Ashlin Harris2023年05月24日 23:11:59 +00:00Commented May 24, 2023 at 23:11
Excel (ms365), 87 bytes
Formula in B1:
=LET(x,CHAR(ROW(97:122)),y,LEN(A1)-LEN(SUBSTITUTE(LOWER(A1),x,)),FILTER(HSTACK(x,y),y))
And 83 bytes if you don't want tupples, but a concatenation would do:
=LET(x,CHAR(ROW(97:122)),y,LEN(A1)-LEN(SUBSTITUTE(LOWER(A1),x,)),FILTER(x&"-"&y,y))
Mapacceptable? \$\endgroup\$