# My daughter's alphabet

The other day we were writing sentences with my daughter with a fridge magnet letter. While we were able to make some(I love cat), we didn't have enough letters to make the others (I love you too) due to an insufficient amount of letters o (4)

I then found out that while one set included 3 e letters it had only 2 o letters. Probably inspired by http://en.wikipedia.org/wiki/Letter_frequency this would still not reflect the actual situation "on the fridge".

## Problem

Given the text file where each line contains a "sample sentence" one would want to write on the fridge, propose an alphabet set with minimum amount of letters but still sufficient to write each sentence individually.

Note: ignore cases, all magnet letters are capitals anyway.

## Input

The file contain newline separated sentences:

hello
i love cat
i love dog
i love mommy


## Output

Provide back sorted list of letters, where each letter appears only as many times to be sufficient to write any sentence:

acdddeghillmmmoostvyy


(thanks, isaacg!)

## Winner

Shortest implementation (code)

### UPDATED: Testing

I have created an extra test and tried with various answers here:

https://gist.github.com/romaninsh/11159751

• There should be a letter v in the output ;) Commented Apr 10, 2014 at 6:35
• Are we allowed / required to substitute an upside-down M for a W, or a sideways N for a Z? ;-) Commented Apr 10, 2014 at 11:42
• Basically you can construct any letter using Is. Commented Apr 10, 2014 at 11:53
• More seriously, when you say "ignore cases", do you mean that we can assume that the input is already all in the same case, or that we must convert it all into the same case? Also, is it OK for the output to include some leading spaces? Commented Apr 10, 2014 at 12:01
• @Doorknob: _\¯ Commented Apr 10, 2014 at 13:37

## PHP, 143 bytes

Assuming that input is passed in variable $s: $i=explode("\n",$s);foreach(range('a','z')as$c){$x=array_map(function($l)use($c){return substr_count($l,$c);},$i);echo str_repeat($c,max($x));}


## Explanation

For each possible letter I'm mapping array containing list of strings through a user-defined function which replaces each line with number of characters used. For letter 'd' the line "Mommy loves daddy" will be mapped into 3.

Afterwards I find maximum value inside array and output letter just this many times. Here is multi-line version:

$i=explode("\n",$s);
foreach(range('A','Z')as $c){$x=array_map(function($l)use($c){
return substr_count($l,$c);
},$i); echo str_repeat($c,max($x)); }  # Jelly, 7, 6, 5 or 4 bytes ỴŒuœ|/Ṣ  Try it online! Function submission. Depending on how you interpret the I/O rules, it may be possible to drop the leading Ỵ (which would then require input to be the data structure "list of strings", as opposed to a single string that was divided using newlines); and it may be possible to drop the Œu (which would then require the input to use a consistent case for the output to be correct). ## Explanation ỴŒuœ|/Ṣ Ỵ Split on newlines Œu Uppercase each resulting string / Combine the resulting strings using… œ| …multiset union Ṣ Sort  • Many answers interpret ignore cases, all magnet letters are capitals anyway as that we don't have to handle input with different cases. The fact that the test case uses lowercase letters supports this interpretation. Commented Dec 13, 2018 at 19:04 • I interpreted the question as requiring you to standardise case (although it didn't matter whether you used uppercase or lowercase). Without that, you can obviously drop the Œu for a 5 or 4 byte solution. Commented Dec 13, 2018 at 19:06 # Julia ## 78 bytes it is my 1st approach !I=join((A='A':'Z').^[max([count(c->c==a,i) for i=split(I,'\n')]...) for a=A]) Attempt This Online! or ## 69 66 bytes • -3 bytes: @MarcMush, thank You • it is inspired by @Laikoni's Haskell answer !I=prod(maximum(filter(==(a),i) for i=split(I,' ')) for a='A':'Z') Attempt This Online! • You can use a literal line break instead of \n and ==(a) instead of c->c==a Commented Jul 29, 2022 at 18:24 # Python (209, with the sample included, 136 without.): from collections import*;c=Counter() for i in ["Hello","I love cat", "I love Dog", "I love mommy", "Mommy loves daddy"]: for j in i.lower(): c[j]=max(c[j],list(i).count(j)) print "".join(sorted(c.elements()))  I'll post a PYG sample this afternoon. • I had no idea Python strings had a count method... I don't suppose it's considered legit to change my answer to the question to use this new found knowledge? :p – Tal Commented Apr 10, 2014 at 7:16 • @tal They don't. It's a method of a list, if you look closer Commented Apr 10, 2014 at 7:17 • Oh, I see... but in an unexpected twist it turns out strings apparently have this method as well (in 3.x anyway) – Tal Commented Apr 10, 2014 at 7:22 # JavaScript, 199 characters function(n){for(s in p=n.toUpperCase(t=[]).split("\n"))for(i in p[k={},s])t[l=p[s][i]]=Math.max(t[l]||0,k[l]=k[l]+1||1);for(l in t)t.push(new Array(t[l]+1).join(l));return t.sort().join('').trim()}  • In Chrome 33, doing for(..in..) on a string results in function properties being accessed. It breaks this solution. The example input from OP gives this result: "ACDDDEGHILLMMMOOSTVYYfunction (){var e=this.toString();if(!arguments.length)return e;var t=typeof arguments[0],n="string"==t||"number"==t?Array.prototype.slice.call(arguments):arguments[0];for(var i in n)e=e.replace(new RegExp("\\{"+i+"\\}","gi"),n[i]);return e}function (e){return this.indexOf(e)>-1}function (e){var t=this.lastIndexOf(e);return 0>t?[this]:[this.substr(0,t),this.substr(t)]}function (e,t){var n=this.toString();re... Commented Apr 10, 2014 at 19:56 # C++, 264 characters. Reads lowercase text from standard input. #include<algorithm> #include<iostream> #include<map> using namespace std;main(){string s;map<int,long> m;while(getline(cin,s)){int c='';while(c++<'z')m[c]=max(m[c],count_if(begin(s),end(s),[c](int d){return d==c;}));}for(auto i:m)cout<<string(i.second,i.first);}  # C++ function, 205 characters. string a(istream&i){string s;map<int,long> m;while(getline(i,s)){int c='';while(c++<'z')m[c]=max(m[c],count_if(begin(s),end(s),[c](int d){return d==c;}));}for(auto i:m)s.append(i.second,i.first);return s;}  # JavaScript - 244 Accepts a parameter of string with newlines. function s(z){n=m="",y=[];z.toLowerCase().split("\n").map(function(g){a=[];g.replace(/ /g,n).split(n).map(function(e,i){if((+y[e]|0)<(a[e]=(+a[e]|0)+1))y[e]=a[e];});});for(var b in y){m+=Array(y[b]+1).join(b);}return m.split(n).sort().join(n);}  Not happy with the sorting and preparation of the output. Edit: case-insensitive regex unnecessary! Thanks @Bergi • Upper- and lowercase spaces in that regex? Commented Apr 10, 2014 at 23:59 # Lua - 206 Chars g=string f,t,b,e=io.lines(({...})[1]),{},g.byte,g.char for s in f do for c=b"a",b"a" do _,d=s:lower():gsub(e(c),"");t[c]=t[c]and(t[c]>d and t[c])or d end end for c=b"a",b"z" do io.write(g.rep(e(c),t[c]))end  Reads from the file passed via command line, then creates a table with the maximum number of occurences per letter. Finally outputs the occuring letters. # Julia, 159 My objective is help understand/improve the expressiveness of Julia. Here's a first attempt. a='a'-1;print(foldl((c,n)->(global a+=1;"$c"*"$a"^n),"",int(mapreduce(s->hist(int({s...}),0:255)[2],(S,T)->max(S,T),zeros(255),readlines(STDIN))[97:122]))"\n")  Here's my crazy idea. Using mapreduce, foldl, and hist (builtin histogram) were advantageous, but having to deal assembling an array from a string and then back to a string from an array and globals expanded the length. Program reads from STDIN. Required foldl which is new in Julia 0.30. ### Sample Input alskdja flkjaslakjd asa as g alkdjaslkajsd  Output aaaddfgjjkkllss  # Java, 335 Here is the executable code in java in a more readable form. Once all the unnecessary white spaces are removed, you will see 335 characters in all. The output is: ACDDDEGHILLMMMOOSTVYY It gets a filename as input and reads each character from the file, converts it to uppercase and stores the count of it's occurrence in an array. For every new line, the maximum occurrence of each character is updated. At last it is printed. Pre-requiste: The file should end with a newline. class F { public static void main(String[] a) throws Exception { java.io.FileInputStream f = new java.io.FileInputStream(a[0]); int j, r, l = 256; int[] i = new int[l], t = new int[l]; while ((r = f.read()) > 0) { r = r > 96 ? r - 32 : r; if (r == 10) for (j = 0; j < l; j++) { i[j] = i[j] < t[j] ? t[j] : i[j]; t[j] = 0; } else t[r]++; } for (j = 65; j < 91; j++) while (i[j]-- > 0) System.out.print((char) j); } }  After removing the white spaces the code will look like the following: class F{public static void main(String[] a)throws Exception{java.io.FileInputStream f=new java.io.FileInputStream(a[0]);int j,r,l=256;int[] i=new int[l],t=new int[l];while((r=f.read())>0){r=r>96?r-32:r;if(r==10)for(j=0;j<l;j++){i[j]=i[j]<t[j]?t[j]:i[j];t[j]=0;}else t[r]++;}for(j=65;j<91;j++)while(i[j]-->0)System.out.print((char)j);}}  # C#, 265 characters Assuming input is in variable s, here's a C# Expression, using mainly LINQ (Enumerable.cs): string.Join("",s.ToLower().Split('\n').Select(e=>e.Where(l=>l!=' '&&l!='\r') .GroupBy(l=>l).ToDictionary(k=>k.Key,v=>v.Count())).SelectMany(u=>u).GroupBy(l=>l.Key) .Select(g=>new String(Enumerable.Range(1,g.Max(v=>v.Value)).Select(i=>g.Key).ToArray())) .OrderBy(l=>l))  # Japt v1.4.5, 11 bytes ;CËpUmèD rw  Try it online! ### Unpacked & How it works ;CmDEF{DpUmèD rw ; Use an alternative set of predefined variables C "abc...z" mDEF{ Map over each char and form a string... UmèD Map over input array into char count rw Reduce with max Dp Repeat the char this number of times  # Powershell, 118116 87 bytes -join($args|%{$_|% t*y|group|%{-join$_.Group}}|sort|group{$_[0]}|%{$_.Group[-1]})|% t*m


Less golfed test script:

$f = {$x=$args|%{$_|% t*y|group|%{-join$_.Group}} # unsorted groups of the same letters for each sentence: (h,e,ll,o), (...), (...), (i, ,l,oo,v,e,d,g),...$y=$x|sort|group{$_[0]}                     # sort all groups and group it again by the first letter (( , , , ), (a,a), (c), (d,ddd), ... (y,yy))
$z=$y|%{$_.Group[-1]} # get a last item (maximum item) from each group -join($z)|% t*m                             # join it and trim spaces

}

@(
,("acdddeghillmmmoostvyy",
"hello",
"i love cat",
"i love dog",
"i love mommy",

"I SAW THE MAN WITH THE BINOCULARS",
"THEY ARE HUNTING DOGS",
"FREE WHALES",
"POLICE HELP DOG BITE VICTIM",
"HE SAW THAT GAS CAN EXPLODE",
"TURN RIGHT HERE",
"WE SAW HER DUCK",
"IN ANIMAL CRACKERS GROUCHO MARX AS CAPTAIN RUFUS T SPAULDING QUIPPED ONE MORNING I SHOT AN ELEPHANT IN MY PAJAMAS HOW HE GOT IN MY PAJAMAS I DONT KNOW",
"SHIP SAILS TOMORROW",
"BOOK STAYS IN LONDON",
"WANTED A NURSE FOR A BABY ABOUT TWENTY YEARS OLD",
"THE GIRL IN THE CAR THAT NEEDED WATER IS WAITING",
"DID YOU EVER HEAR THE STORY ABOUT THE BLIND CARPENTER WHO PICKED UP HIS HAMMER AND SAW",
"THOSE PROSECUTORS HAVE BEEN TRYING TO LOCK HIM UP FOR TEN YEARS",
"FLYING PLANES CAN BE DANGEROUS",
"I ONCE SAW A DEER RIDING MY BICYCLE",
"TOILET OUT OF ORDER PLEASE USE FLOOR BELOW",
"LOOK AT THE DOG WITH ONE EYE")
) | %{
$expected,$s = $_$result = &$f @s "$($result-eq$expected): $result" }  Output: True: acdddeghillmmmoostvyy True: AAAAAAAAAAAAAAAABBBCCCCDDDDDEEEEEEEEEFFGGGGHHHHHHIIIIIIIIIIJJKKLLLLMMMMMMMNNNNNNNNNNNNNOOOOOOOOOPPPPPPPQRRRRRRSSSSSSSTTTTTTUUUUUVWWXYYY  # Vyxalas, 12 bytes ȧ∑U:ƛ?vOG;*s  Try it Online!  U # Unique characters of... ȧ∑ # The input, with whitespace removed * # Repeated by... :ƛ ; # Themselves mapped to... G # The highest... vO # Amount of... # (implicit) That character ? # In the input s # Sorted.  # Japt-Px, 9 8 bytes I knew there had to be a way to to it in 8! cü üÎËÍÌ  Try it cü üÎËÍÌ :Implicit input of array c :Flat map ü : Group & sort by value ü :Group & sort by Î : First character Ë :Map Í : Sort Ì : Last element :Implicitly join, trim and output  ## Original (w/o flags), 9 bytes Takes input as an array of lowercase strings. ;C£ËoXÃÍo  Try it ;C£ËoXÃÍo :Implicit input of array U ;C :Lowercase alphabet £ :Map each X Ë : Map U oX : Remove all characters but X Ã : End inner map Í : Sort o : Pop last element  # JavaScript (Node.js), 95 bytes a=>(g=i=>i?g(i-1,i=i.toString(36))+i.repeat(Math.max(...a.map(y=>y.split(i).length))-1):'')(35)  Try it online! # C# - 146 Bytes var x="";foreach(var l in File.ReadAllLines(t))foreach(var p in l)if(x.Count(c=>c==p)<l.Count(c=>c==p))x+=p;string.Concat(x.OrderBy(o=>o)).Trim();  Well, I think this is as short as C# can get. This code expects a path to the text file in the variable t. # Kotlin, 189 bytes lines().map{it.filter{it.isLetter()}.groupingBy{it}.eachCount()}.fold(mutableMapOf<Char,Int>()){r,i->i.map{(t,u)->r[t]=maxOf(r[t] ?:0,u)} r}.flatMap{(k,v)->(0..v-1).map{k}}.joinToString("")  ## Beautified lines() .map { it.filter { it.isLetter() }.groupingBy { it }.eachCount() } .fold(mutableMapOf<Char, Int>()) { r, i -> i.map { (t, u) -> r[t] = maxOf(r[t] ?: 0, u)} r } .flatMap { (k, v) -> (0..v-1).map { k } } .joinToString("")  ## Test fun String.f() = lines().map{it.filter{it.isLetter()}.groupingBy{it}.eachCount()}.fold(mutableMapOf<Char,Int>()){r,i->i.map{(t,u)->r[t]=maxOf(r[t] ?:0,u)} r}.flatMap{(k,v)->(0..v-1).map{k}}.joinToString("") fun main(args: Array<String>) { val i = """hello i love cat i love dog i love mommy mommy loves daddy""" println(i.f().map { it }.sorted().joinToString("")) println("acdddeghillmmmoostvyy") }  ## TIO TryItOnline # C# / LINQPad, 181 bytes In C# Expression mode; assumes input file is named a (and probably in the LINQPad Program Files folder) string.Join("",File.ReadAllLines("a").SelectMany(s=>s.ToUpper().Where(c=>c>64&&c<91).GroupBy(c=>c)).GroupBy(g=>g.Key).Select(g=>new string(g.Key,g.Max(x=>x.Count()))).OrderBy(s=>s))  ### Ungolfed string.Join("", // concat all substrings, with no separator File.ReadAllLines("a") // read all lines from text file called 'a' .SelectMany( // apply function to each subset and union into a single set s => s.ToUpper() // convert strings to uppercase .Where(c => c > 64 && c < 91) // shorter than char.IsLetter(c) for all uppercase .GroupBy(c => c) // group on each character in the string ) .GroupBy(g => g.Key) // group again on each character (I'd love to get rid of this...) .Select(g => new string(g.Key, g.Max(x => x.Count()))) // string(char, count) constructor build repeating-char string .OrderBy(s => s) // sorted set required )  ### Input (text file called a) Hello I love cat I love dog I love mommy Mommy loves daddy  ### Output ACDDDEGHILLMMMOOSTVYY  # C, 298 bytes (242 bytes by not counting newlines) Array D keeps tally of letters in each line, then the maximum count of each letter is copied into array C. char c; int j,n; char C[26]; char D[26]; int main() { char a='a'; while((c=getchar())>=0) { c=tolower(c); if(c>=a&&c<='z'){j=c-a;D[j]++;} if(c=='\n'){ for(j=0;j<26;j++){ if(D[j]>C[j]) {C[j]=D[j];} D[j]=0; } } } for(j=0;j<26;j++) { n=C[j]; while(n--) { putchar(a+j); } } }  Note: I just discovered Notepad++ which gives my character count, counts newlines as 2 chars. Should these be subtracted? • That's because you use CRLF (Windows) line terminators. You should tell Notepad++ to use LF (Unix), then they will only count as one character. – user344 Commented Apr 21, 2014 at 20:00 # Stax, 8 bytes ü2lLÜ▀⌂æ  Run and debug it 1. Reduce the array of inputs using a multiset union operation. 2. Sort the resulting characters. 3. Remove spaces. # PHP, 116 bytes foreach(file(T)as$y=>$s)for($i=0;~$c=ucfirst($s[$i++]);)$$c[y]++;for(c=A;!c[1];c++)echo str_repeat(c,max($$c));  assumes filename T. Run with -nr. breakdown foreach(file(T)as$y=>$s) # loop through lines of file for($i=0;~$c=ucfirst($s[$i++]);) # loop through line characters $$c[y]++; # increment counter (A..Z) for(c=A;!c[1];c++) # loop c through uppercase letters echo str_repeat(c,max($$c)); # get max from$A, \$B etc, use as multiplier for str_repeat


# JavaScript, 105 104 bytes

Takes input as an array of character arrays and returns a string.

a=>[...new Set(a+)].sort().map(c=>c.repeat(a.map(r=w=>r=w.map(l=>o+=c>{}&c==l,o=0)|o<r?r:o)|r)).join


Try it online

# Pyth, 14 10 bytes

[email protected]


Accepts input as lowercase strings. Try it online here.

[email protected]   Implicit: .z=input as list of strings, G=lowercase alphabet
m       G   Map each letter in G, as d, using:
L .z      In each string in .z ...
@ d        ... keep only those characters which match d
S           Sort by length
e            Take the last element (i.e. longest)
s            Concatenate into string, implicit print


Edit: golfed 3 bytes. Previous version: sm*[email protected]

# Vyxals, 5 bytes

ɾƒÞ∪s


Try it Online!

# jq, 94 bytes

[.,inputs]|map(explode-[32]|group_by(.)[])|group_by(.[0])|map(max_by(length)|implode)|join("")


Try it online!

[., inputs]                          # from raw input to array of strings
# e.g. ["hello", "i love cat", …]

| map(explode-[32] | group_by(.)[])  # splits each string into groups of
# similar codepoints (excluding spaces)
# e.g. "hello" -> [[101],[104],[108,108],[111]]

| group_by(.[0])                     # groups all groups of similar codepoints

| map(max_by(length)|implode)        # then only keep the largest group of
# each sub groups and transform the
# group into a string

| join("")                           # finally join all the strings


# Thunno 2J, 7 bytes

ẠıȷcGn×


Attempt This Online!

Port of Kevin Cruijssen's 05AB1E answer.

#### Explanation

ẠıȷcGn×  # Implicit input
Ạı       # Map over lowercase alphabet:
ȷc     #  Count in each input string
G    #  Pop and leave the maximum
n×  #  Repeat the character that many times
# Implicit output, joined