Code Golf, выпуск 4 июля: подсчет десяти наиболее часто встречающихся слов

Учитывая следующий список президентов, подсчитайте первые десять слов в наименьшей возможной программе:

ВХОДНОЙ ФАЙЛ

    Washington
    Washington
    Adams
    Jefferson
    Jefferson
    Madison
    Madison
    Monroe
    Monroe
    John Quincy Adams
    Jackson
    Jackson
    Van Buren
    Harrison 
    DIES
    Tyler
    Polk
    Taylor 
    DIES
    Fillmore
    Pierce
    Buchanan
    Lincoln
    Lincoln 
    DIES
    Johnson
    Grant
    Grant
    Hayes
    Garfield 
    DIES
    Arthur
    Cleveland
    Harrison
    Cleveland
    McKinley
    McKinley
    DIES
    Teddy Roosevelt
    Teddy Roosevelt
    Taft
    Wilson
    Wilson
    Harding
    Coolidge
    Hoover
    FDR
    FDR
    FDR
    FDR
    Dies
    Truman
    Truman
    Eisenhower
    Eisenhower
    Kennedy 
    DIES
    Johnson
    Johnson
    Nixon
    Nixon 
    ABDICATES
    Ford
    Carter
    Reagan
    Reagan
    Bush
    Clinton
    Clinton
    Bush
    Bush
    Obama

Чтобы начать с bash 97 символов

cat input.txt | tr " " "\n" | tr -d "\t " | sed 's/^$//g' | sort | uniq -c | sort -n | tail -n 10

Вывод:

      2 Nixon
      2 Reagan
      2 Roosevelt
      2 Truman
      2 Washington
      2 Wilson
      3 Bush
      3 Johnson
      4 FDR
      7 DIES

Разорвите связи, как считаете нужным! Счастливый четвертый!

Те из вас, кому небезразлична дополнительная информация о президентах, могут найти здесь.


person Community    schedule 04.07.2009    source источник
comment
Разве список не должен различать Буша-младшего и старшего?   -  person gnovice    schedule 04.07.2009
comment
Кроме того, разве Рузвельт тоже не умер? кажется, что многие решения не читают вопрос, многие ответы не разбивают слова, а просто сортируют список после группы.   -  person jasonmw    schedule 04.07.2009
comment
Хех FDR FDR FDR FDR Это было по памяти Я знаю... Я согласен с обоими пунктами, но в духе веселья... пусть так и будет...   -  person ojblass    schedule 04.07.2009
comment
@Джоусон, мы отредактируем вопрос на свое усмотрение...   -  person ojblass    schedule 04.07.2009
comment
Хорошая работа по памяти, хотя я слишком нуб, чтобы ее редактировать. Я пойду с вариантом пусть это будет.... :)   -  person jasonmw    schedule 05.07.2009
comment
Dupe: stackoverflow.com/questions/1038252/   -  person Sampson    schedule 05.07.2009


Ответы (16)


Укороченная версия оболочки:

xargs -n1 < input.txt | sort | uniq -c | sort -nr | head

Если вы хотите ранжировать без учета регистра, измените uniq -c на uniq -ci.

Еще немного короче, если вы довольны обратным рангом и ухудшением читаемости из-за отсутствия пробелов. Это соответствует 46 символам:

xargs -n1<input.txt|sort|uniq -c|sort -n|tail

(Вы могли бы сократить это число до 38, если бы вам разрешили сначала переименовать входной файл в просто «i».)

Заметив, что в этом особом случае ни одно слово не встречается более 9 раз, мы можем сократить еще 3 символа, отбросив аргумент '-n' из окончательной сортировки:

xargs -n1<input.txt|sort|uniq -c|sort|tail

Это сокращает это решение до 43 символов без переименования входного файла. (Или 35, если вы это сделаете.)

Использование xargs -n1 для разделения файла на одно слово в каждой строке предпочтительнее решения tr \ \\n, так как это создает много пустых строк. Это означает, что решение неверно, потому что оно пропускает Никсона и показывает пустую строку, появляющуюся 256 раз. Однако пустая строка не является «словом».

person Community    schedule 04.07.2009
comment
Использование xargs разумно — оно работает, даже если данные пронизаны начальными и конечными пробелами. И это хорошее наблюдение, что только 'tail' печатает последние десять строк вывода (я забыл); что экономит еще 4 персонажа. - person Jonathan Leffler; 04.07.2009
comment
Есть ли способ обмануть и использовать xargs внутри vim и потерять длину имени файла? - person ojblass; 04.07.2009

C#, 153:

Считывает файл по адресу p и выводит результаты на консоль:

File.ReadLines(p)
    .SelectMany(s=>s.Split(' '))
    .GroupBy(w=>w)
    .OrderBy(g=>-g.Count())
    .Take(10)
    .ToList()
    .ForEach(g=>Console.WriteLine(g.Count()+"|"+g.Key));

Если просто создать список, но не печатать на консоли, это 93 символа.

6|DIES
4|FDR
3|Johnson
3|Bush
2|Washington
2|Adams
2|Jefferson
2|Madison
2|Monroe
2|Jackson
person Community    schedule 04.07.2009
comment
Моя главная претензия к Java и CSharp заключается в их многословности... не могли бы вы сократить это с помощью эквивалента использования...? - person ojblass; 04.07.2009
comment
Довольно аккуратно и аккуратно, подумал я. И хотя бы полупонятный, по крайней мере по сравнению с Perl-версией. - person Jonathan Leffler; 04.07.2009
comment
«ReadLines» должно быть «ReadAllLines». Кроме того, это может быть немного короче, если вы удалите .ToList(), так как вы можете использовать foreach для IEnumerable, который возвращает Take. Итак: foreach (var v в File.ReadAllLines(p).SelectMany(s =› s.Split(' ')) .GroupBy(w =› w) .OrderBy(g =› -1 * g.Count()) .Take(10)) Console.WriteLine(v.Count() + | + v.Key); - person JulianR; 04.07.2009
comment
@JulianR: ReadLines кажется допустимым, поскольку такая функция указана в .NET 4.0: msdn.microsoft.com/en-us/library/dd383503%28VS.100%29.aspx - person Ahmad Mageed; 04.07.2009
comment
@ Ахмад - Странно. Так в чем разница между ReadAllLines и ReadLines и почему они добавили это в .NET 4.0? Единственная разница в том, что один возвращает IENumerable‹string›, а другой — строку[]? - person JulianR; 05.07.2009
comment
@JulianR: См. Lippert здесь: блоги .msdn.com/ericlippert/archive/2008/09/22/ - person jason; 05.07.2009

вим 60

    :1,$!tr " " "\n"|tr -d "\t "|sort|uniq -c|sort -n|tail -n 10
person Community    schedule 04.07.2009
comment
:1,$! можно заменить на :%!, не так ли? - person ephemient; 14.09.2009

Вим 36

:%s/\W/\r/g|%!sort|uniq -c|sort|tail
person Community    schedule 04.07.2009
comment
с учетом этого ввода это работает, но не создает ли это опасность лексической сортировки чисел? - person ojblass; 04.07.2009
comment
абсолютно. но /учитывая этот ввод/, я могу обойтись без этих дополнительных трех символов :) - person Josef Pfleger; 04.07.2009
comment
Вы можете потерять 4 символа, потому что «хвост» эквивалентен «хвост -10» или «хвост -n10». - person Jonathan Leffler; 04.07.2009
comment
ха! конечно, спасибо. удалил его и вернул числовую сортировку для ojblass - person Josef Pfleger; 04.07.2009
comment
хм, тебе не хватает двоеточия... ненавижу, когда пропускаю двоеточие - person ojblass; 04.07.2009
comment
'-n' (и пробел) в этом примере не нужны, потому что все счетчики представляют собой одиночные цифры и лексическую ‹==› числовую сортировку, когда это так. - person Jonathan Leffler; 05.07.2009
comment
это то, что у меня было изначально, пока ОП не пожаловался, но я согласен с вами, поэтому я удалил это - person Josef Pfleger; 05.07.2009
comment
Мне это нравится, но парень xargs понимает... ты получаешь второе место... Счастливого четвертого! - person ojblass; 05.07.2009
comment
Это умно, но, к сожалению, дает тот же неверный результат, что и решение с использованием tr - оно создает 256 пустых строк и ошибочно показывает эти слова, пропуская Никсона из результатов. - person Stig Brautaset; 07.07.2009

Haskell, 102 символа (вау, так близко к оригиналу):

import List
(take 10.map snd.sort.map(\(x:y)->(-length y,x)).group.sort.words)`fmap`readFile"input.txt"

J, всего 55 символов:

10{.\:~~.(,.~[:<"0@(+/)=/~);;:&.><;._2[1!:1<'input.txt'

(Мне еще предстоит выяснить, как элегантно выполнять манипуляции с текстом в J... он намного лучше работает с данными, структурированными в виде массива.)


   NB. read the file
   <1!:1<'input.txt'
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------...
|    Washington     Washington     Adams     Jefferson     Jefferson     Madison     Madison     Monroe     Monroe     John Quincy Adams     Jackson     Jackson     Van Buren     Harrison DIES     Tyler     Polk     Taylor DIES     Fillmore     Pierce     ...
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------...
   NB. split into lines
   <;._2[1!:1<'input.txt'
+--------------+--------------+---------+-------------+-------------+-----------+-----------+----------+----------+---------------------+-----------+-----------+-------------+-----------------+---------+--------+---------------+------------+----------+----...
|    Washington|    Washington|    Adams|    Jefferson|    Jefferson|    Madison|    Madison|    Monroe|    Monroe|    John Quincy Adams|    Jackson|    Jackson|    Van Buren|    Harrison DIES|    Tyler|    Polk|    Taylor DIES|    Fillmore|    Pierce|    ...
+--------------+--------------+---------+-------------+-------------+-----------+-----------+----------+----------+---------------------+-----------+-----------+-------------+-----------------+---------+--------+---------------+------------+----------+----...
   NB. split into words
   ;;:&.><;._2[1!:1<'input.txt'
+----------+----------+-----+---------+---------+-------+-------+------+------+----+------+-----+-------+-------+---+-----+--------+----+-----+----+------+----+--------+------+--------+-------+-------+----+-------+-----+-----+-----+--------+----+------+---...
|Washington|Washington|Adams|Jefferson|Jefferson|Madison|Madison|Monroe|Monroe|John|Quincy|Adams|Jackson|Jackson|Van|Buren|Harrison|DIES|Tyler|Polk|Taylor|DIES|Fillmore|Pierce|Buchanan|Lincoln|Lincoln|DIES|Johnson|Grant|Grant|Hayes|Garfield|DIES|Arthur|Cle...
+----------+----------+-----+---------+---------+-------+-------+------+------+----+------+-----+-------+-------+---+-----+--------+----+-----+----+------+----+--------+------+--------+-------+-------+----+-------+-----+-----+-----+--------+----+------+---...
   NB. count reptititions
   |:~.(,.~[:<"0@(+/)=/~);;:&.><;._2[1!:1<'input.txt'
+----------+-----+---------+-------+------+----+------+-------+---+-----+--------+----+-----+----+------+--------+------+--------+-------+-------+-----+-----+--------+------+---------+--------+---------+----+------+-------+--------+------+---+------+------...
|2         |2    |2        |2      |2     |1   |1     |2      |1  |1    |2       |6   |1    |1   |1     |1       |1     |1       |2      |3      |2    |1    |1       |1     |2        |2       |2        |1   |2     |1      |1       |1     |4  |2     |2     ...
+----------+-----+---------+-------+------+----+------+-------+---+-----+--------+----+-----+----+------+--------+------+--------+-------+-------+-----+-----+--------+------+---------+--------+---------+----+------+-------+--------+------+---+------+------...
|Washington|Adams|Jefferson|Madison|Monroe|John|Quincy|Jackson|Van|Buren|Harrison|DIES|Tyler|Polk|Taylor|Fillmore|Pierce|Buchanan|Lincoln|Johnson|Grant|Hayes|Garfield|Arthur|Cleveland|McKinley|Roosevelt|Taft|Wilson|Harding|Coolidge|Hoover|FDR|Truman|Eisenh...
+----------+-----+---------+-------+------+----+------+-------+---+-----+--------+----+-----+----+------+--------+------+--------+-------+-------+-----+-----+--------+------+---------+--------+---------+----+------+-------+--------+------+---+------+------...
   NB. sort
   |:\:~~.(,.~[:<"0@(+/)=/~);;:&.><;._2[1!:1<'input.txt'
+----+---+-------+----+------+----------+------+---------+------+-----+------+--------+-------+-------+---------+-------+--------+-----+----------+-------+---------+-----+---+-----+------+----+------+----+------+-----+-------+----+------+-----+-------+----...
|6   |4  |3      |3   |2     |2         |2     |2        |2     |2    |2     |2       |2      |2      |2        |2      |2       |2    |2         |2      |2        |2    |1  |1    |1     |1   |1     |1   |1     |1    |1      |1   |1     |1    |1      |1   ...
+----+---+-------+----+------+----------+------+---------+------+-----+------+--------+-------+-------+---------+-------+--------+-----+----------+-------+---------+-----+---+-----+------+----+------+----+------+-----+-------+----+------+-----+-------+----...
|DIES|FDR|Johnson|Bush|Wilson|Washington|Truman|Roosevelt|Reagan|Nixon|Monroe|McKinley|Madison|Lincoln|Jefferson|Jackson|Harrison|Grant|Eisenhower|Clinton|Cleveland|Adams|Van|Tyler|Taylor|Taft|Quincy|Polk|Pierce|Obama|Kennedy|John|Hoover|Hayes|Harding|Garf...
+----+---+-------+----+------+----------+------+---------+------+-----+------+--------+-------+-------+---------+-------+--------+-----+----------+-------+---------+-----+---+-----+------+----+------+----+------+-----+-------+----+------+-----+-------+----...
   NB. take 10
   10{.\:~~.(,.~[:<"0@(+/)=/~);;:&.><;._2[1!:1<'input.txt'
+-+----------+
|6|DIES      |
+-+----------+
|4|FDR       |
+-+----------+
|3|Johnson   |
+-+----------+
|3|Bush      |
+-+----------+
|2|Wilson    |
+-+----------+
|2|Washington|
+-+----------+
|2|Truman    |
+-+----------+
|2|Roosevelt |
+-+----------+
|2|Reagan    |
+-+----------+
|2|Nixon     |
+-+----------+
person Community    schedule 05.07.2009
comment
Я полагаю, что наиболее очевидная проблема заключается в том, что поток символов не имеет смысла без знания набора символов и словаря J... но в остальном это не так уж плохо. Существуют ли какие-либо языки, которые продвигают поддерживаемые однострочники? - person ephemient; 05.07.2009
comment
ну, мой ответ дает наиболее читаемое решение этой проблемы. - person SilentGhost; 05.07.2009
comment
Для обратного порядка, который использует OP, замените 10{.\:~ на 10{:/:~ - person ephemient; 05.07.2009

Perl: 90

Perl: 114 (включая perl, переключатели командной строки, одинарные кавычки и имя файла)

perl -nle'$h{$_}++for split/ /;END{$i++<=10?print"$h{$_} $_":0for reverse sort{$h{$a}cmp$h{$b}}keys%h}' input.txt
person Community    schedule 04.07.2009
comment
Несколько простых приемов уменьшают всю команду до 84: perl -ne'$_{$_.$/}++for+split}print+(sort{$_{$b}‹=›$_{$a}} ключи%_)[0..9];{' input.txt - person ephemient; 05.07.2009

Отсутствие AWK настораживает.

xargs -n1<input.txt|awk '{c[$1]++}END{for(p in c)print c[p],p|"sort|tail"}'

75 символов.

Если вы хотите получить немного больше AWKy, вы можете забыть об xargs:

awk -v RS='[^a-zA-Z]' /./'{c[$1]++}END{for(p in c)print c[p],p|"sort|tail"}' input.txt
person Community    schedule 05.07.2009
comment
получить ваш awk на! эээ, это немного страшно... Счастливый Четвертый! - person ojblass; 05.07.2009

Пока что моя лучшая попытка с рубином, 166 символов:

h = Hash.new
File.open('f.l').each_line{|l|l.split(/ /).each{|e|h[e]==nil ?h[e]=1:h[e]+=1}}
h.sort{|a,b|a[1]<=>b[1]}.last(10).each{|e|puts"#{e[1]} #{e[0]}"}

Я удивлен, что никто еще не опубликовал сумасшедшее решение J.

person Community    schedule 04.07.2009
comment
вы можете заменить первую строку на h = {} - person Cuervo's Laugh; 05.07.2009
comment
Кроме того, вы можете заменить бит .each_line, указав это для первой строки: File.open('f.1').each {|l|l.split(/ /).each{|e|h[e] ==nil ?h[e]=1:h[e]+=1}} экономит 4 символа - person Cuervo's Laugh; 05.07.2009

Вот сжатая версия сценария оболочки, отметив, что для разумной интерпретации входных данных (без начальных или конечных пробелов) вторая команда «tr» и «sed» в оригинале не изменяют данные (проверено путем вставки 'tee out.N' в подходящих точках и проверка размеров выходного файла - идентично). Оболочке требуется меньше места, чем людям, а использование cat вместо перенаправления ввода-вывода тратит пространство впустую.

tr \  \\n<input.txt|sort|uniq -c|sort -n|tail -10

Это весит 50 символов, включая новую строку в конце скрипта.

Еще два наблюдения (из ответов других людей):

  1. tail сам по себе эквивалентен 'tail -10', и
  2. в этом случае числовая и альфа-сортировка эквивалентны,

это может быть сокращено еще на 7 символов (до 43, включая завершающую новую строку):

tr \  \\n<input.txt|sort|uniq -c|sort|tail

Использование 'xargs -n1' (без указания префикса команды) вместо 'tr' чрезвычайно умно; он имеет дело с ведущими, конечными и несколькими встроенными пробелами (чего нет в этом решении).

person Community    schedule 04.07.2009

vim 38 и работает для всех входных

:%!xargs -n1|sort|uniq -c|sort -n|tail
person Community    schedule 04.07.2009

Python 2.6, 104 символа:

l=open("input.txt").read().split()
for c,n in sorted(set((l.count(w),w) for w in l if w))[-10:]:print c,n
person Community    schedule 04.07.2009
comment
там вообще не нужно. посмотри мой ответ. - person SilentGhost; 04.07.2009

python 3.1 (88 символов)

import collections
collections.Counter(open('input.txt').read().split()).most_common(10)
person Community    schedule 04.07.2009
comment
Счетчик находится в коллекциях, а не в itertools. Это также не печатает вывод и в обратном порядке по сравнению с выводом исходного вопроса. - person truppo; 05.07.2009
comment
да, это была опечатка. но не вижу смысла удовлетворять все прихоти ОП. Почему в порядке возрастания, а не убывания? он печатает при запуске в интерпретаторе. - person SilentGhost; 05.07.2009

Perl 86 символов

94, если считать имя входного файла.

perl -anE'$_{$_}++for@F;END{say"$_{$_} $_"for@{[sort{$_{$b}<=>$_{$a}}keys%_]}[0..10]}' test.in

Если вам все равно, сколько результатов вы получите, то их всего 75, не считая имени файла.

perl -anE'$_{$_}++for@F;END{say"$_{$_} $_"for sort{$_{$b}<=>$_{$a}}keys%_}' test.in
person Community    schedule 05.07.2009

Рубин 66Б

puts (a=$<.read.split).uniq.map{|x|"#{a.count x} "+x}.sort.last 10
person Community    schedule 07.07.2009

Рубин

115 символов

w = File.read($*[0]).split
w.uniq.map{|x| [w.select{|y|x==y}.size,x]}.sort.last(10).each{|z| puts "#{z[1]} #{z[0]}"}
person Community    schedule 10.07.2009

Пакетный файл Windows

Это явно не самое маленькое решение, но я все же решил его выложить, просто ради интереса. :) NB: пакетный файл использует временный файл с именем $ для хранения временных результатов.

Оригинальная несжатая версия с комментариями:

@echo off
setlocal enableextensions enabledelayedexpansion

set infile=%1
set cnt=%2
set tmpfile=$
set knownwords=

rem Calculate word count
for /f "tokens=*" %%i in (%infile%) do (
  for %%w in (%%i) do (

    rem If the word hasn't already been processed, ...
    echo !knownwords! | findstr "\<%%w\>" > nul
    if errorlevel 1 (

      rem Count the number of the word's occurrences and save it to a temp file
      for /f %%n in ('findstr "\<%%w\>" %infile% ^| find /v "" /c') do (
        echo %%n^|%%w >> %tmpfile%
      )

      rem Then add the word to the known words list
      set knownwords=!knownwords! %%w
    )
  )
)

rem Print top 10 word count
for /f %%i in ('sort /r %tmpfile%') do (
  echo %%i
  set /a cnt-=1
  if !cnt!==0 goto end
)

:end
del %tmpfile%

Сжатая и запутанная версия, 317 символов:

@echo off&setlocal enableextensions enabledelayedexpansion&set n=%2&set l=
for /f "tokens=*" %%i in (%1)do for %%w in (%%i)do echo !l!|findstr "\<%%w\>">nul||for /f %%n in ('findstr "\<%%w\>" %1^|find /v "" /c')do echo %%n^|%%w>>$&set l=!l! %%w
for /f %%i in ('sort /r $')do echo %%i&set /a n-=1&if !n!==0 del $&exit /b

Его можно сократить до 258 символов, если эхо уже отключено, а расширения команд и раскрытие переменных с задержкой включены:

set n=%2&set l=
for /f "tokens=*" %%i in (%1)do for %%w in (%%i)do echo !l!|findstr "\<%%w\>">nul||for /f %%n in ('findstr "\<%%w\>" %1^|find /v "" /c')do echo %%n^|%%w>>$&set l=!l! %%w
for /f %%i in ('sort /r $')do echo %%i&set /a n-=1&if !n!==0 del $&exit /b

Использование:

> filename.bat input.txt 10 & pause

Вывод:

6|DIES
4|FDR
3|Johnson
3|Bush
2|Wilson
2|Washington
2|Truman
2|Roosevelt
2|Reagan
2|Nixon
person Community    schedule 29.07.2009
comment
Я вернулся, оглядываясь на этот пост, и я отчасти рад, что сделал это. Вы проделали очень хорошую работу, сделав это на действительно отсталом языке. - person ojblass; 30.04.2010