Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

The code should take input a text (not mandatory can be anything file, stdin, string for JavaScript, etc):

This is a text and a number: 31.

The output should contain the words with their number of occurrence, sorted by the number of occurrences in descending order:

a:2
and:1
is:1
number:1
This:1
text:1
31:1

Notice that 31 is a word, so a word is anything alpha-numeric, number are not acting as separators so for example 0xAF qualifies as a word. Separators will be anything that is not alpha-numeric including .(dot) and -(hyphen) thus i.e. or pick-me-up would result in 2 respectively 3 words. Should be case sensitive, This and this would be two different words, ' would also be separator so wouldnand t will be 2 different words from wouldn't.

Write the shortest code in your language of choice.

share|improve this question
5  
Does case matter (ie is This the same as this and tHIs)? –  Gareth Jan 29 at 7:49
    
If anything non-alphanumeric counts as a separator, is wouldn't 2 words (wouldn and t)? –  Gareth Jan 29 at 7:51
    
@Gareth Should be case sensitive, This and this would be indeed two different words, same wouldnand t. –  Eduard Florinescu Jan 29 at 9:08
    
If Wouldn't are 2 words, shouldn't it be "Would" and "nt" since its short for Would not, or is that to much grammer nazi-ish? –  Teun Pronk Jan 29 at 9:12
    
@TeunPronk I try to keep it simple, putting a few rules will encourage exceptions to be in order with grammar , and there are a lot of exceptions out there.Ex in English i.e. is a word but if we let the dot all the dots at the end of phrases will be taken, same with quotes or single quotes, etc. –  Eduard Florinescu Jan 29 at 9:18
show 6 more comments

41 Answers

grep and coreutils  44  42

grep -io '[a-z0-9]*'|sort|uniq -c|sort -nr

Test:

printf "This is a text and a number: 31." |
grep -io '[a-z0-9]*'|sort|uniq -c|sort -nr

Results in:

  2 a
  1 This
  1 text
  1 number
  1 is
  1 and
  1 31

Update

  • Use case-insensitive option and shorter regex. Thanks Tomas.
share|improve this answer
2  
This being almost exactly McEllroy's response to Knuth's book Literate Programming. The only difference being that this does not include a pipe into head at the end. –  AJMansfield Jan 29 at 10:54
    
This was pretty much my first thought too. –  Rob Jan 29 at 17:15
1  
Wouldn't '\w+' work as well? –  Sylwester Jan 30 at 18:05
1  
41 characters: grep -io \[A-Z0-9]*|sort|uniq -c|sort -nr –  Tomas Feb 1 at 16:16
1  
@Tomas: Added this to the answer, thanks. I left in protection for the asterisk, because it was expanding file names in some shells. –  Thor Feb 26 at 10:10
show 2 more comments

Java 8: 289

Which is pretty good, since java is a very non-golfy language.

import java.util.stream.*;class C{static void main(String[]a){Stream.of(a).flatMap(s->of(s.split("[\\W_]+"))).collect(Collectors.groupingBy(x->x,Collectors.counting())).entrySet().stream().sorted(x,y->x.getValue()-y.getValue()).forEach(e->System.out.println(e.getKey()+":"+e.getValue()));}

Ungolfed:

import java.util.stream.*;
class C {
    static void main(String [] args){
        Stream.of(args).flatMap(arg->Stream.of(arg.split("[\\W_]+")))
            .collect(Collectors.groupingBy(word->word,Collectors.counting()))
            .entrySet().stream().sorted(x,y->x.getValue()-y.getValue())
            .forEach(entry->System.out.println(entry.getKey()+":"+entry.getValue()));
    }
}

Run from the command line:

java -jar wordCounter.jar This is a text and a number: 31.
share|improve this answer
    
Wrong regex for splitting. It should be "[^\\W_]" –  n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 24 at 22:40
    
@n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳, the String.split(String regex) method takes a pattern that matches the delimiter to split on. So, for instance, "aababba".split("b") would yield the array {"aa", "a", "", "a"}. My regex [^\\w\\d] means 'a character in neither the word character nor digit character classes'. [^\\W_] is instead 'a character that is neither an underscore nor is in the non-word-character class' and would match any word character except the underscore. –  AJMansfield Mar 25 at 16:10
    
Sorry, my previous comment was incorrect. \w includes \d, so \d is redundant. \w includes underscore, which should be considered a separator according to the question. So the correct regex for splitting should be "[\\W_]+". –  n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 25 at 16:30
    
@n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ ok, thanks; I've fixed the problem. –  AJMansfield Mar 25 at 18:47
add comment

APL (57)

⎕ML←3⋄G[⍒,1↓⍉G←⊃∪↓Z,⍪+⌿∘.≡⍨Z←I⊂⍨(I←⍞)∊⎕D,⎕A,⎕UCS 96+⍳26;]

e.g.

      ⎕ML←3⋄G[⍒,1↓⍉G←⊃∪↓Z,⍪+⌿∘.≡⍨Z←I⊂⍨(I←⍞)∊⎕D,⎕A,⎕UCS 96+⍳26;]
This is a text and a number: 31.
 a       2
 This    1
 is      1
 text    1
 and     1
 number  1
 31      1

Explanation:

  • ⎕D,⎕A,⎕UCS 96+⍳26: numbers, uppercase letters, lowercase letters
  • (I←⍞)∊: read input, store in I, see which ones are alphanumeric
  • Z←I⊂⍨: split I in groups of alphanumeric characters, store in Z
  • +⌿∘.≡⍨Z: for each element in Z, see how often it occurs
  • Z,⍪: match each element in Z pairwise with how many times it occurs
  • G←⊃∪↓: select only the unique pairs, store in G
  • ⍒,1↓⍉G: get sorted indices for the occurrences
  • G[...;]: reorder the lines of G by the given indices
share|improve this answer
5  
what... the... f..... –  Ozh Jan 30 at 10:49
5  
This is why I have nightmares. –  Thebluefish Jan 30 at 14:50
2  
@Thebluefish: APL was designed from a notation, with the intention that much like maths, a concise notation frees you to think clearly. Again like maths, when you first see that notation, you tend to think it's not clear at all, but languages always seem complex to begin with. It would be easier if it wasn't all on one line, though... –  Phil H Feb 3 at 15:01
add comment

C#: 153c 144c 142c 111c 115c 118c 114c 113c

(via LINQPad in "C# Statements" mode, not including input string)

Version 1: 142c

var s = "This is a text and a number: 31."; // <- line not included in count
s.Split(s.Where(c=>!Char.IsLetterOrDigit(c)).ToArray(),(StringSplitOptions)1).GroupBy(x=>x,(k,e)=>new{s,c=e.Count()}).OrderBy(x=>-x.c).Dump();

Ungolfed:

var s = "This is a text and a number: 31.";
s.Split(                                                     // split string on multiple separators
    s.Where(c => !Char.IsLetterOrDigit(c))                   // get list of non-alphanumeric characters in string
     .ToArray(),                                             // (would love to get rid of this but needed to match the correct Split signature)
    (StringSplitOptions)1                                    // integer equivalent of StringSplitOptions.RemoveEmptyEntries
).GroupBy(x => x, (k, e) => new{ s = k, c = e.Count() })     // count by word
 .OrderBy(x => -x.c)                                         // order ascending by negative count (i.e. OrderByDescending)
 .Dump();                                                    // output to LINQPad results panel

Results:

Results

Version 2: 114c

([\w] includes _, which is incorrect!; [A-z] includes [ \ ] ^ _ `; settling on [^_\W]+)

var s = "This is a text and a number: 31."; // <- line not included in count
Regex.Matches(s, @"[^_\W]+").Cast<Match>().GroupBy(m=>m.Value,(m,e)=>new{m,c=e.Count()}).OrderBy(g=>-g.c).Dump();

Ungolfed:

Regex.Matches(s, @"[^_\W]+")                                   // get all matches for one-or-more alphanumeric characters
     .Cast<Match>()                                            // why weren't .NET 1 collections retrofitted with IEnumerable<T>??
     .GroupBy(m => m.Value, (m,e) => new{ m, c = e.Count() })  // count by word
     .OrderBy(g => -g.c)                                       // order ascending by negative count (i.e. OrderByDescending)
     .Dump();                                                  // output to LINQPad results panel

Results: (as Version 1)

share|improve this answer
    
By the way, for version 2, your ungolfed version does not match your golfed version. And since you are using literal string, you can write @"[^_\W]" –  n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 25 at 10:14
    
@n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ - fixed the typo and removed the extra `` for a 1-char saving -- thanks!! –  jimbobmcgee Mar 26 at 19:40
add comment

R, 58 char

sort(table(unlist(strsplit(scan(,""),"[[:punct:]]"))),d=T)

Usage:

sort(table(unlist(strsplit(scan(,""),"[[:punct:]]"))),d=T)
1: This is a text and a number: 31.
9: 
Read 8 items

     a     31    and     is number   text   This 
     2      1      1      1      1      1      1 
share|improve this answer
    
+1 for using R - brave! –  Tomas Feb 1 at 16:17
add comment

perl6: 49 characters

.say for get.comb(/\w+/).Bag.pairs.sort(-*.value)

Comb input for stuff matching \w+, put resulting list of words in a Bag, ask for their pairs and sort them by negative value. (The * is a Whatever star, it's not multiplication here)

output:

"a" => 2
"This" => 1
"is" => 1
"text" => 1
"and" => 1
"number" => 1
"31" => 1
share|improve this answer
3  
Perl 6 scares me. –  primo Jan 29 at 19:24
1  
Every time I think of a cool language feature, I look for it and it's in Perl6 somewhere. That's why it's taking a long time... –  Phil H Jan 30 at 13:49
    
You can trim 6 characters by using .words instead of .comb(/\w+/) :) –  Mouq Feb 15 at 23:42
    
@Mouq: unfortunately .words doesn't strip the : or . from the input as required :( –  Ayiko Feb 15 at 23:59
    
-1. _ should not be included in a word under the problem statement. –  n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 24 at 22:24
add comment

Python 101 97

import re
a=re.split('[_\W]+',input())
f=a.count
for w in sorted(set(a),key=f)[::-1]:print w,f(w)

Now works with newline:

$ python countword.py <<< '"This is    a text and a number: 31, and a\nnewline"'
a 3
and 2
31 1
number 1
newline 1
is 1
text 1
This 1
share|improve this answer
    
This doesn't work when there are newlines or more than one consecutive space in text. –  klingt.net Jan 30 at 12:17
    
@klingt.net fixed. –  daniero Jan 30 at 13:03
add comment

PHP - 84 bytes

<?$a=array_count_values(preg_split('/[_\W]+/',$argv[1],0,1));arsort($a);print_r($a);

Input is accepted as a command line argument, e.g.:

$ php count-words.php "This is a text and a number: 31."

Output for the sample string:

Array
(
    [a] => 2
    [number] => 1
    [31] => 1
    [and] => 1
    [text] => 1
    [is] => 1
    [This] => 1
)
share|improve this answer
1  
it says input is what you want. so you can get it as command line parameter using $argv[1] –  Einacio Jan 29 at 19:13
    
@Einacio good call. –  primo Jan 29 at 19:17
    
-1. Underscore _ should not be included in a word. –  n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 24 at 22:25
    
@n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ fixed. –  primo Mar 29 at 9:07
add comment

PowerShell (40)

$s -split"\W+"|group -ca|sort count -des

$s is a variable that contains the input string.

share|improve this answer
2  
[\W] isn't good enough - it is matching a space in my test. And it is not ordered by descending count... –  jimbobmcgee Jan 29 at 21:09
    
$s -split"[\W]"|group -ca|where{$_.Name -ne ""}|sort{-$_.Count} gets you closer (with costs, of course) –  jimbobmcgee Jan 29 at 21:21
    
Ooops I missed the sorting part. Will fix my answer shortly. –  microbian Jan 29 at 21:32
    
alternatively: $s -split"\W+"|group -ca |sort count -des –  Nacimota Jan 29 at 23:00
4  
-split"\W+" is matching an empty string between the last . and the end of the string; also \W+ matches _ which is technically not allowed –  jimbobmcgee Jan 30 at 1:07
add comment

Powershell: 57 55 53 62 57

(not including input string)

$s = "This is a text and a number: 31."    # <-- not counting this line...
[Regex]::Matches($s,"[^_\W]+")|group -ca|sort{-$_.Count}

returns:

Count Name                      Group
----- ----                      -----
    2 a                         {a, a}
    1 and                       {and}
    1 31                        {31}
    1 number                    {number}
    1 This                      {This}
    1 is                        {is}
    1 text                      {text}

(with props to @microbian for group -ca)

share|improve this answer
add comment

EcmaScript 6

Version 1 (108 characters)

s.split(_=/[^a-z\d]/i).map(x=>_[x]=-~_[x]);keys(_).sort((a,b)=>_[a]<_[b]).map(x=>x&&console.log(x+':'+_[x]))

Version 2 (102 characters)

s.split(_=/[^a-z\d]/i).map(x=>_[x]=-~_[x]);keys(_).sort((a,b)=>_[a]<_[b]).map(x=>x&&alert(x+':'+_[x]))

Version 3 (105 characters)

s.match(_=/\w+/g).map(x=>_[x]=-~_[x]);alert(keys(_).sort((a,b)=>_[a]<_[b]).map(x=>x+':'+_[x]).join('\n'))

Version 4 (94 characters)

s.match(_=/\w+/g).map(x=>_[x]=-~_[x]);keys(_).sort((a,b)=>_[a]<_[b]).map(x=>alert(x+':'+_[x]))

Version 5 (without alert; 87 characters)

s.match(_=/\w+/g).map(x=>_[x]=-~_[x]);keys(_).sort((a,b)=>_[a]<_[b]).map(x=>x+':'+_[x])

Version 6 (100 characters)

keys(_,s.match(_=/\w+/g).map(x=>_[x]=-~_[x])).sort((a,b)=>_[a]<_[b]).map(x=>console.log(x+':'+_[x]))

Output:

a:2
31:1
This:1
is:1
text:1
and:1
number:1
share|improve this answer
    
You can change _[a] and _[b] to _.a and _.b. Also changing /\w+/g,_={} to _=/\w+/g will produce the same result. –  eithedog Jan 29 at 18:15
    
@eithedog Thank you! However, I can't change _[a] to be _.a because it tries to access the property "a" of _, not the property a. –  toothbrush Jan 29 at 18:33
    
ah, correct - the order won't be kept. Carry on :) –  eithedog Jan 29 at 19:16
    
Oh, I didn't notice your answer.. nice. But.. is Object.keys becoming a global in ES6? Your answer seems to assume this, but I don't recall seeing that as scheduled for ES6. –  FireFly Jan 29 at 21:03
    
@FireFly I can't find any documentation, but it works fine in Firefox. I haven't tested it in Chrome/Opera/IE. –  toothbrush Jan 29 at 21:19
show 1 more comment

Groovy 77 82

changed regex from [^\w]+ to [^\d\p{L}]+ in order to solve problem with underscore

String s = 'This is a text and a number: 31'

def a=s.split(/[^\d\p{L}]+/) 
a.collectEntries{[it, a.count(it)]}.sort{-it.value}

without first line, 82 characters

output:

[a:2, This:1, is:1, text:1, and:1, number:1, 31:1]
share|improve this answer
    
nu_ber is not alphanumeric. This shouls be 2 words –  Cruncher Jan 29 at 13:52
    
Why use nu_ber instead of number? –  Kevin Fegan Jan 29 at 19:42
    
I was mislead by some other posts ;) now I removed the "_" from the input, but fixed the regex to handle it –  Kamil Mikolajczyk Jan 29 at 20:18
add comment

Perl 69

$h{$_}++for<>=~/\w+/g;print"$_: $h{$_}
"for sort{$h{$b}-$h{$a}}keys%h

Added recommendations from @primo and @protist

share|improve this answer
1  
What about sorting? –  daniero Jan 29 at 11:52
    
@daniero, excellent point! This now sorts! –  Dom Hastings Jan 29 at 11:56
1  
I think that's about as terse as it can get. If you don't mind a deprecation warning, no space is required between ge and for. Also, the <=> operator can be replaced by -. –  primo Jan 29 at 13:43
2  
@primo Ahhh - instead of <=> is genius, not sure that's on the golfing tips for Perl thread. I'll update this later, thanks! –  Dom Hastings Jan 29 at 14:32
1  
Hey @protist, \w includes numbers too (perl -e 'print for"a 1 2 3 4 b"=~/\w/g' prints a1234b), but your mechanism for iterating the words saves another character so I'll update. Thank you! –  Dom Hastings Jan 31 at 8:49
show 2 more comments

GNU awk + coreutils: 71 69

gawk 'BEGIN{RS="\\W+"}{c[$0]++}END{for(w in c)print c[w],w}'|sort -nr

Although gawk asort works on associative arrays, it apparently does not preserve the index values, necessitating the external sort

printf "This is a text and a number: 31." | 
gawk 'BEGIN{RS="\\W+"}{c[$0]++}END{for(w in c)print c[w],w}'|sort -nr
2 a
1 This
1 text
1 number
1 is
1 and
1 31

GNU awk 4.x: 100 93

A slightly larger but pure gawk solution using PROCINFO to set the default sort order for the associative array (appears to require a relatively recent gawk - > 4.x?)

BEGIN{RS="\\W+";PROCINFO["sorted_in"]="@val_num_desc"}
{c[$0]++}
END{for(w in c)print c[w],w}
share|improve this answer
    
Oooooh. I didn't know about PROCINFO. As if I needed another excuse to use awk in my life. Curse you! –  dmckee Feb 1 at 7:50
    
@dmckee TBH I didn't know about PROCINFO until I started poking around - I was convinced there had to be a way to do the sort natively - just a pity the identifiers are so long ;) –  steeldriver Feb 1 at 14:55
    
In the bad old days there simply wasn't a way. Which leads to things like this old answer of mine. –  dmckee Feb 1 at 17:00
    
-1. Underscore _ should not be included in a word. –  n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 24 at 22:26
add comment

Javascript - 132 126 chars !

(Shortest JS code)

o={},a=[]
for(i in s=s.split(/[\W_]+/))o[z=s[i]]=o[z]+1||1
for(j in o)a.push([j,o[j]])
a.sort(function(b,c){return c[1]-b[1]})

Improved the regex and some edits.


Ungolfed

s = s.split(/[\W_]+/), o={}, a=[]; // split along non-char letters, declare object and array

for (i in s) { n = s[i]; o[n] = o[n] + 1 || 1 } // go through each char and store it's occurence

for (j in o) a.push( [j, o[j]] ); // store in array for sorting

a.sort(function (b, c){ return c[1] - b[1]; }); // sort !

<= // make s = "How shiny is this day is isn't is"

=> [ [ 'is', 3 ],
[ 'How', 1 ],
[ 'shiny', 1 ],
[ 'this', 1 ],
[ 'day', 1 ],
[ 'isn', 1 ],
[ 't', 1 ] ]


Old - 156 143 141 140 132 chars

s=s.split(/[^\w]+/g),o={}
for(i in s){n=s[i];o[n]=o[n]+1||1}a=[]
for(j in o)a.push([j,o[j]])
a.sort(function(b,c){return c[1]-b[1]})

Gave a first try at golfing. Feedback appreciated.

share|improve this answer
add comment

EcmaScript 6, 115 100 87 (without prompt&alert)

Thanks to @eithedog:

s.match(/\w+/g,a={}).map(w=>a[w]=-~a[w]),keys(a).map(w=>[w,a[w]]).sort((a,b)=>b[1]-a[1])

With prompt and alert (100):

prompt(a={}).match(/\w+/g).map(w=>a[w]=-~a[w]);alert(keys(a).map(w=>[w,a[w]]).sort((a,b)=>b[1]-a[1]))

Run it in Firefox.

share|improve this answer
1  
You don't need var . Also, you can move a={} inside prompt - prompt(a={}). You can also drop Object. and change w=>a[w]=a[w]+1||1 to w=>a[w]=-~a[w] –  eithedog Jan 29 at 17:06
    
Very nice. Beats the working Python one now :) –  teh_senaus Jan 29 at 17:36
    
Same as for @toothbrush's answer - moving the declaration of a from prompt to regexp will spare two more chars. –  eithedog Jan 29 at 18:18
    
It's nice and clean. Good job! –  toothbrush Jan 29 at 19:03
    
-1. Underscore _ should not be included in a word. –  n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 24 at 22:27
add comment

Ruby 58 82 65

h=Hash.new 0
gets.scan(/[\d\w]+/){h[$&]+=1}
p *h.sort_by{|k,v|-v}

Test run:

$ ruby counttext.rb <<< "This is a text and a number: 31."
["a", 2]
["text", 1]
["This", 1]
["is", 1]
["and", 1]
["number", 1]
["31", 1]

Edit 58->80: Ok, I was way off. I forgot to sort the words by occurrences. Also, Array#uniq is not an enumerator, but uses a given block to compare elements, so passing puts to it didn't filter out duplicates (not that it says that we should).

share|improve this answer
    
Maybe split(/\W+/) instead of scan (untested)? –  Howard Jan 29 at 8:51
    
@Howard Thanks. \W excludes _ so that had to be fixed, but it still saved 2 characters (then I added 20 to fix the sorting that I had neglected). –  daniero Jan 29 at 9:43
    
Shouldn't be sorted in reverse (a=gets.split(/[_\W]+/)).uniq.map{|w|[w,a.count(w)]}.sort_by(&:last).reverse.ma‌​p{|x|p x} –  Eduard Florinescu Jan 29 at 10:59
    
@EduardFlorinescu Nah. reverse is way too verbose ;) Btw, it's not fair changing the question. –  daniero Jan 29 at 11:47
    
If you see in the output sample it was sorted descended only that I forgot to specify it. –  Eduard Florinescu Jan 29 at 11:52
show 3 more comments

F# - 169

let f s=(s+"").Split(set s-set(['a'..'z']@['A'..'Z']@['0'..'9'])|>Set.toArray)|>Seq.where((<>)"")|>Seq.countBy id|>Seq.sortBy((~-)<<snd)|>Seq.iter((<||)(printfn"%s:%d"))

Degolfed:

let count (s : string) =
    s.Split (set s - set (['a'..'z']@['A'..'Z']@['0'..'9']) |> Set.toArray)
 |> Seq.where ((<>) "")
 |> Seq.countBy id
 |> Seq.sortBy ((~-) << snd)
 |> Seq.iter ((<||) (printfn "%s:%d"))

Output when called from fsi:

> "This is a text and a number: 31." |> f
a:2
This:1
is:1
text:1
and:1
number:1
31:1
val it : unit = ()

Update: Some explanation as requested in the comments.

Uses set functions to generate an array of non alphanumeric characters in the input to pass to String.Split, then uses sequence functions to filter out empty strings, generate word counts and print the result.

Some golfing tricks: Adds an empty string to the function argument s to force type inference of the argument as a string rather than explicitly declaring the type. Uses Seq.where rather than Seq.filter to save a few characters (they are synonyms). Mixes forward pipe and ordinary function application in an attempt to minimize characters. Uses currying and (op) syntax to treat <> ~- and <|| operators as regular functions to avoid declaring lambdas to filter empty strings, sort by descending count and print tuples.

share|improve this answer
    
You should definitely insert some sort of explanation; that way we can understand your code. –  Quincunx Jan 30 at 0:43
    
Added a degolfed version and some explanation. –  mattnewport Jan 30 at 5:54
add comment

Python - 95 ( now 87 thanks to @primo)

d=__import__('re').findall(r'\w+',raw_input())
print sorted(map(lambda y:(y,d.count(y)),d))

Sample input :

'This is a text and a number: 31'

Sample output :

[('This', 1),('is', 1), ('a', 2),('text', 1),('and', 1),('a', 2),('number', 1),('31', 1)]

Any improvement sugestion would be appreciated

share|improve this answer
1  
The solution is nice but the output is not sorted. –  Eduard Florinescu Jan 29 at 14:04
    
What do you mean by sorted? Thanks for the comment. –  Azwr Jan 29 at 14:09
1  
\w matches [a-zA-Z0-9_]. Your entire regex can be replaced by r'\w+'. Also, the x variable is not needed, just use raw_input() as the second parameter to findall. –  primo Jan 29 at 14:15
    
By sorted, the OP means that the words that appear most often need to be listed first. Also, your program should include a print statement (i.e. print map(...), otherwise it's not a complete program. –  primo Jan 29 at 14:22
    
I don't have time to sort it right now :( I'm in a hurry , thanks for the suggestions and comments. –  Azwr Jan 29 at 14:24
show 3 more comments

JavaScript 160 144 (Edited: to meet requirements)

f=Function;o={};s.replace(/\w+/g,f('a','o[a]=++o[a]||1'));Object.keys(o).sort(f('b,c','return o[c]-o[b]')).map(f('k','console.log(k+" "+o[k])'))

Unminified:

f=Function;
o = {};
s.replace(/\w+/g, f('a','o[a]=++o[a]||1'));
Object.keys(o).sort(f('b,c', 'return o[c]-o[b]')).map(f('k','console.log(k+" "+o[k])'))

Logs each word to console in order, passing the following string:

s="This is sam}}ple text 31to test the effectiveness of this code, you can clearly see that this is working-as-intended, but you didn't doubt it did you?.";

Outputs:

you 3
this 2
is 2
can 1
text 1
31to 1
test 1
the 1
effectiveness 1
of 1
This 1
code 1
sam 1
ple 1
clearly 1
see 1
that 1
working 1
as 1
intended 1
but 1
didn 1
t 1
doubt 1
it 1
did 1 

I don't have the heart to use alert().

share|improve this answer
1  
The sort should be by the number. of occurrences so you should be first. –  Eduard Florinescu Jan 29 at 16:15
    
@EduardFlorinescu Silly me... I'll fix it later. –  George Reith Jan 29 at 16:56
    
@EduardFlorinescu fixed –  George Reith Jan 30 at 10:22
    
-1. Underscore _ should not be included in a word. –  n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 24 at 22:29
add comment

k [71 chars]

f:{s:" ",x;`_k!m@k:|(!m)@<.:m:#:'=`$1_'(&~((),/:s)like"[a-zA-Z0-9]")_s}

Any other character except alphanumeric chars will be considered as delimiter.

example

f "This is a text and a number: 31."
a     | 2
31    | 1
number| 1
and   | 1
text  | 1
is    | 1
This  | 1

example

f "won't won won-won"
won| 4
t  | 1
share|improve this answer
add comment

Javascript (135)

u=/\w+/g
for(i=s.length;i--;)for(w in a=s.match(u))u[w=a[w]]=u[w]||a.reduce(function(p,c){return p+=w==c},0)==i&&!console.log(w+":"+i)

Unminified:

u=/\w+/g;for (i=s.length;i--;)
    for(w in a=s.match(u))
        u[w=a[w]] = u[w] || 
           a.reduce(function(p,c){return p+=w==c},0)==i && !console.log(w+":"+i)

Loops over every possible number of matches in descending order, and outputs words with that number of occurrences. Just to be horrible.

Notes: Alert would have reduced the length some. Strictly speaking alphanumeric should be [^\W_]

share|improve this answer
add comment

Haskell (153 = 104 code + 49 import)

Pretty straight-forward, totally composed function... no argument even necessary! This is my first golf, so go easy, maybe? :)

import Data.Char
import Data.List
import Data.Ord
so=reverse.(sortBy$comparing snd).(map(\t@(x:_)->(x,length t))).group.sort.(map$filter isAlphaNum).words

Output:

*Main> so "This is a text and a number: 31."
[("a",2),("text",1),("number",1),("is",1),("and",1),("This",1),("31",1)]
share|improve this answer
add comment

q (50)

desc count each group" "vs ssr[;"[^0-9A-Za-z]";" "]
  • ssr replaces non alphanumeric
  • " "vs splits the result into a symbol list
  • count each group counts creates a dict matching distinct elements of the list with the number of occurances
  • desc sorts the dict by descending values

edit: fixed accidentally matching ascii 58-64 and 91-96

share|improve this answer
1  
I've no knowledge of q but is the regex [0-z] ASCII-based? If it is, wouldn't it also include ASCII chars 58-64? Because those are : ; < = > ? @. –  jimbobmcgee Feb 3 at 12:08
    
Great catch jimbob, thanks –  nightTrevors Feb 3 at 21:40
    
You're welcome; only spotted because I found the same in C#. Sadly, same with [A-z], which matches ASCII 91-96, which are `[ \ ] ^ _ `` –  jimbobmcgee Feb 3 at 21:51
    
ah right you are, nice little ascii lesson right there! –  nightTrevors Feb 3 at 22:23
    
I just discovered [^_\W]+ for mine, which should be "exclude non-word characters and underscore", if your syntax supports the \W class... –  jimbobmcgee Feb 3 at 23:09
add comment

Pure Bash (no external programs), 164

This is longer than I'd hoped, but I wanted to see if the necessary counting and sorting (in the right direction) could be done purely with bash arrays (associative and non-associative):

declare -A c
for w in ${@//[[:punct:]]/ };{ ((c[$w]++));}
for w in ${!c[@]};{ i=${c[$w]};((m=i>m?i:m));s[$i]+=$w:;}
for((i=m;i>0;i--));{ printf "${s[i]//:/:$i
}";}

Save as a script file, chmod +x, and run:

$ ./countoccur This is a text and a number: 31.
a:2
and:1
number:1
text:1
31:1
is:1
This:1
$ 
share|improve this answer
add comment

AWK

awk -vRS='[^A-Za-z0-9]' '$0{c[$0]++}END{for(i in c)print c[i]"\t"i": "c[i]|"sort -nr|cut -f2-"}'

Does the job without gawkish extensions:

$ echo 'This is a text and a number: 31.' | awk -vRS='[^A-Za-z0-9]' '$0{c[$0]++}END{for(i in c)print c[i]"\t"i": "c[i]|"sort -nr|cut -f2-"}'
a: 2
This: 1
text: 1
number: 1
is: 1
and: 1
31: 1

If printing "count: word" instead, it would be a bit shorter but I wanted to mimic the given example output...

share|improve this answer
add comment

Python 2.X (108 - Characters)

print'\n'.join('{}:{}'.format(a,b)for a,b in __import__("collections").Counter(raw_input().split()).items())

Python 3.X (106 - Characters)

print('\n'.join('{}:{}'.format(a,b)for a,b in __import__("collections").Counter(input().split()).items())
share|improve this answer
    
Separators will be anything that is not alpha-numeric - You only split on whitespace. –  daniero Jan 29 at 11:43
add comment

Python 3 - 76

The requirement of splitting on non-alphanumeric chars unfortunately extends the code by 19 chars. The output of the following is shown correctly. If you are not sure, add a .most_common() after the .Counter(...).

i=__import__
print(i('collections').Counter(i('re').findall('\w+',input())))

In/Output

Given the input of This is a text and a number: 31. you get following output:

Counter({'a': 2, 'is': 1, 'This': 1, 'and': 1, '31': 1, 'number': 1, 'text': 1})

I tried it with other values like

1 2 3 4 5 6 7 8 2 1 5 3 4 6 8 1 3 2 4 6 1 2 8 4 3 1 3 2 5 6 5 4  2 2 4 2 1 3 6

to ensure, the output-order does not rely on the key's value/hash. This example produces:

Counter({'2': 8, '3': 6, '1': 6, '4': 6, '6': 5, '5': 4, '8': 3, '7': 1})

But as I said, print(i('collections').Counter(i('re').findall('\w+',input())).most_common()) would return the results as an definitly ordered list of tuples.


Python 3 - 57 (if a space would be enough for splitting :P)

print(__import__('collections').Counter(input().split()))
share|improve this answer
    
If you assumed the string was in some variable s, as some other answers do, you could lose 6 characters by replacing input(). –  Phil H Jan 31 at 8:24
    
@PhilH well. you are right, but I would never read that out of the requirements. sure the "string for JavaScript"-part might suggest it, but I cannot, with a clear conscience, interpret a string-variable as a valid "input". But you are right. that would shorten it even more. :P –  Dave J Jan 31 at 19:43
    
-1. Underscore _ should not be included in a word. –  n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Mar 24 at 22:31
    
Well this depends on the definition of alpha-numeric. In Python, "\w" is defined for accepting alpha-numeric chars. You might be correct but a with this kind of interpretation of the rules, my solution keeps being correct. :) –  Dave J Mar 26 at 15:20
add comment

J, 35+?

(~.(([\:]);]\:]),.@(+/"1@=))@(>@;:)

Doesn't fully work though. Problem is that the splitting into words ';:' monad doesn't handle non-alplanumeric characters in quite the right way. Any suggestions?

Here's how you use it:

(~.(([\:]);]\:]),.@(+/"1@=))@(>@;:) 'This is a text and a number: 31.'
┌───────┬─┐
│a      │2│
│This   │1│
│is     │1│
│text   │1│
│and    │1│
│number:│1│
│31.    │1│
└───────┴─┘ 
share|improve this answer
add comment

Clojure

(defn wc [s]
  (let [mc #(assoc % %2 (inc (get % %2 0)))]
    (sort-by #(- (val %))
             (reduce mc {} (re-seq #"\w+" (.toLowerCase s))))))

example:

(wc "hi mom hi dad hello peter hello dad hi")
;; (["hi" 3] ["hello" 2] ["dad" 2] ["peter" 1] ["mom" 1])
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.