Найти столбцы, где все символы одинаковы


18

Я наткнулся на этот вопрос на SO и подумал, что это будет хорошим испытанием для гольфа. Итак, вот оно:

Вызов:

Напишите программу, которая читает последовательность строк символов, по одной на строку, и выводит список всех позиций, где каждая строка имеет один и тот же символ.

Вход и выход:

Ввод состоит из одной или нескольких строк печатных непробельных символов ASCII, за которыми следует новая строка. Вы можете предположить, что все входные строки имеют одинаковую длину. Новая строка не должна рассматриваться как часть ввода (т.е. вы не должны выводить ее как соответствующий символ).

Пример ввода (бесстыдно украденный из SO вопроса):

abcdefg
avcddeg
acbdeeg

После прочтения ввода ваша программа должна напечатать позиции каждого соответствующего столбца и символы, которые они содержат. (Ваша программа может, но не обязательно, прекратить чтение дополнительных входных данных, если она может определить на ранней стадии, что нет соответствующих столбцов.) Разрешен любой разумный выходной формат; в частности, вы можете использовать индексацию на основе 0 или 1 для позиций.

Пример вывода для указанного выше ввода (с использованием индексации на основе 0):

0: a
3: d
6: g

Подсчет очков:

Это код гольф, поэтому самый короткий ответ выигрывает. В случае ничьей могут быть присуждены дробные чары с прерывателем связи за дополнительные функции:

  • −½ символа для правильной обработки строк ввода неравной длины. (Вывод не должен содержать позиций после конца самой короткой строки ввода.)
  • - символы для правильной обработки ввода, состоящего из произвольных символов Unicode в кодировке UTF-8.

Для вдохновения, вы можете найти некоторые безрассудные решения в вопросе SO (см. Выше).

Разъяснения:

  • Простое объединение позиций и символов, как в 0a3d6g, не считается «разумным выводом». Вы должны предоставить какой-то разделитель (например, пробел) между каждым элементом выходных данных, чтобы его можно было однозначно проанализировать.

  • Ввод будет предоставлен в стандартном потоке ввода ( stdin) или с использованием любого механизма ввода текстового файла, наиболее естественного для вашего языка. (Если выбранный вами язык не имеет естественного механизма ввода файлов, делайте то, что кажется вам наиболее подходящим.)

  • Ввод заканчивается, когда больше нет данных для чтения (т. Е. Когда возникает условие конца файла). Если вы хотите, вы можете потребовать, чтобы ввод был завершен пустой строкой (которую вы тогда не должны считать частью ввода, очевидно). Если вы это сделаете, пожалуйста, укажите это в своем ответе, чтобы другие могли предоставить правильные данные для тестирования.

  • Каждая строка ввода, включая последнюю, заканчивается символом новой строки. Ваш ответ не должен сообщать об этой новой строке как соответствующий столбец. (Хорошо, если ваше решение может также обрабатывать ввод, когда последняя строка не заканчивается новой строкой, но это не обязательно.)


Так пустая строка завершает ввод?
Стивен Румбальски

«Вы должны обеспечить какой-то разделитель между каждым элементом вывода, чтобы его можно было однозначно проанализировать». Считается ли пространство разделителем?
Стивен Румбальски

@StevenRumbalski: ввод заканчивается, когда больше нет данных для чтения; Я полагаю, что могу разрешить в конце пробел, если ваш язык не может определить EOF. И да, пробел является отличным разделителем.
Ильмари Каронен

Можем ли мы иметь произвольный пример кода в кодировке UTF-8 Unicode?
пользователь неизвестен

Ответы:


12

APL, 25 символов

∩/{0=⍴⍵:⍬⋄(⊂⍵,⍨¨⍳⍴⍵),∇⍞}⍞

Я использовал Dyalog APL (версия 13) в качестве моего переводчика. Он обрабатывает как вводы неравной длины, так и символы Unicode (UTF-8).

Примеры:

      ∩/{0=⍴⍵:⍬⋄(⊂⍵,⍨¨⍳⍴⍵),∇⍞}⍞
abcdefg
avcddeg
acbdeeg

  1 a  4 d  7 g  

      ∩/{0=⍴⍵:⍬⋄(⊂⍵,⍨¨⍳⍴⍵),∇⍞}⍞
test日本
blat日本国foo

  4 t  5 日  6 本 

Пояснение, несколько справа налево:

  • Основная часть этого ответа - прямая функция (в основном, анонимная функция), определенная в фигурных скобках. Правильный аргумент указан как .
    • 0=⍴⍵:⍬это наше первое выражение, и оно проверяет, получили ли мы пустую строку (то есть, мы закончили). Он использует охрану (знакомая конструкция для многих функциональных программистов) для условного выполнения выражения справа от двоеточия. В этом случае, если 0 равно shape / length ( ) правого аргумента, мы возвращаем пустой set ( ).
    • разделяет два выражения внутри функции. Если предыдущее выражение не было оценено (и, следовательно, ничего не возвращало), мы переходим к следующему выражению.
    • Мы рекурсивно вызываем функцию с помощью функции self-reference ( ). Аргументом функции является строка необработанного пользовательского ввода, заданного quote-quad ( ).
    • ⊂⍵,⍨¨⍳⍴⍵ создает пары для каждого символа в строке, где первый элемент каждой пары - это ее позиция в строке, а ее второй элемент - это символ.
    • ⍳⍴⍵дает вектор от 1 до ⍴⍵или длину входной строки.
    • ⍵,⍨¨применяет коммутируемую функцию конкатенации ( ,⍨) к каждому ¨элементу ( ) слева ( в данном случае от пользователя) и справа. При переключении функции конкатенации ее левый и правый аргументы меняются местами.
    • Наконец, мы заключаем результат, используя , чтобы мы могли различать строки ввода.
  • Первоначально мы кормим нашу функцию пользовательским вводом ( ).
  • Наконец, мы уменьшаем ( /) наш результирующий вектор векторов пар, используя функцию пересечения ( ), получая пары, найденные во всех субвекторах.

Без всякой уважительной причины у меня возникает внутренний отрицательный ответ, когда я вижу APL, которого у меня нет для J или GolfScript. Но +1 в любом случае для отличного решения.
Стивен Румбальски

Я действительно думал о переходе на J ... Я добавлю это в свой список причин. :)
Диллон Кауэр

12

Golfscript (28 символов)

n/zip:^,,{.^=.&.,1>{;;}*}%n*

Существуют проблемы с набором символов при прохождении Юникода, поэтому нет бонуса в четверть очка.


1
+1. Это не должно иметь меньше голосов, чем мой ответ.
Стивен Румбальский

9

J, 57 51 44 40 символов

,.&.>y;y{{.z[y=.I.*/2=/\]z=.];._2]1!:1]3

Я добираюсь туда медленно, но верно. Это все еще далеко от идеала, хотя я думаю.

Я был уверен, что использование крючка будет ответом, но, к сожалению, нет (44 символа):

,.&.>((];({{.)~)([:I.[:*/2=/\]))];._2]1!:1]3

Мне может понадобиться совершенно другой метод, чтобы стать короче.


1
+1. Но да, я ожидаю лучшего от J.
Стивен Румбальски

Это не должно иметь меньше голосов, чем мой ответ.
Стивен Румбальский

1
@StevenRumbalski Апвот не всегда отражает относительные размеры кода. Иногда это становится конкурсом популярности языка. Я согласен с тем, что ответ по сценарию гольфа должен быть наверху с APL, к сожалению, я уже дал ему свое одобрение и не могу помочь поднять его дальше.
Гарет

8

Хаскель, 64 символа

main=interact$show.foldl1(filter.flip elem).map(zip[0..]).lines

Обрабатывает линии неравной длины. Поддержка Unicode зависит от текущих настроек локали.

Пример вывода:

[(0,'a'),(3,'d'),(6,'g')]

+1. Это не должно иметь меньше голосов, чем мой ответ.
Стивен Румбальский

7

Python 2, оценка 81,5 ( 116 94 86 83 82 байта минус бонус)

import sys
i=0
for x in zip(*sys.stdin)[:-1]:
 i+=1
 if len(set(x))<2:print i,x[0]

+1 для хорошего Python golf, но вы можете потерять целых ЧЕТЫРЕ персонажа: [:-1]нет необходимости, если только вычеркнуть посторонний символ новой строки в конце ввода (чего, похоже, даже нет в вопросе).
ChristopheD

@ChristopheD: На самом деле, результат zip(*sys.stdin)есть [('a', 'a', 'a'), ('b', 'v', 'c'), ('c', 'c', 'b'), ('d', 'd', 'd'), ('e', 'd', 'e'), ('f', 'e', 'e'), ('g', 'g', 'g'), ('\n', '\n', '\n')]. Я не вижу способа избежать того, чтобы убирать последний кортеж новых строк. Пожалуйста, поправьте меня, если я неправильно понял. Спасибо за отзыв.
Стивен Румбальски

Если удалить последнюю строку в файле данных кортеж для этой строки не завершен (промахи один «\ п» так пронестись только рассматривает и возвращает данные , которые мы ищем, что позволяет удаление [:-1]Eg.zip([1,2,3,4],[1,2,3])=> [(1, 1), (2, 2), (3, 3)]
ChristopheD

@ChristopheD: Согласно спецификации, «ввод состоит из [...] строк [...], за которыми следует новая строка».
Илмари Каронен

1
Человек, который отклонил этот ответ, объяснит почему?
Стивен Румбальски

5

(Bash) Shell Scripting, 105 символов

Если у кого-то есть еще какие-то хитрости, пожалуйста, оставьте комментарий!

for((i=1;i<`tail -1 $1|wc -c`;i++))do
x="cut -c$i $1";y=`$x`;[ `$x|uniq|wc -l` = 1 ]&& echo $i ${y:3};done

Результат:

1 а
4 д
7 г

У меня проблемы с тем, чтобы заставить это работать; Выполнение этого на вводе образца печатает серию ошибок, подобных /tmp/cols.sh: line 2: [1: command not foundи ничего более.
Ильмари Каронен

@Ilmari Karonen: это было протестировано на Mac (снежный барс, 10.6.2), но должно работать в другом месте. Завтра я исправлю это в Linux (должно быть небольшое исправление)
ChristopheD

2
У ormaaj не хватило представителя, но он хотел прокомментировать: он сломался для Ilmari из-за недостатка места после [; и $ {y: 3} заставит его работать только с 3 строками ввода. Исправление и оптимизация доходностей (100 символов) while((++i%`tail -1 $1|wc -c`));do x=`cut -c$i $1`;((`uniq|wc -l`==1))<<<"$x"&&echo $i ${x: -1};doneи использование значений по умолчанию должны позволить сохранить еще один, for((;++i<`tail -1 $1|wc -c`;))doно в bash есть нефиксированная ошибка.
Питер Тейлор

4

Perl, 87 символов (−½ бонуса на тай-брейк)

Вот версия моего собственного решения для гольфа из SO SO :

chomp($a=$b=<>);$a&=$_,$b|=$_ for<>;@$_=$$_=~/./sgfor a,b;$b[$i++]eq$_&&say"$i:$_"for@a

В отличие от версии SO, в этой версии для вывода используются индексы на основе 1. Он использует sayфункцию Perl 5.10 , поэтому должен быть запущен с perl -M5.010(или с perl -E).

Как вариант SO, этот код ручки переменной длины линии, и будет обрабатывать произвольный ввод Unicode , если стандартный вход и выход были в режиме UTF-8. Увы, по умолчанию это не так, если только не указан несвободный -CS ключ командной строки. Таким образом, он зарабатывает бонус-1/2 символа, но не бонус -¼.

Изменить: +1 символ, чтобы исправить ошибку: только потому, что входные строки не содержат перевода строки, не означает, что они не могут в конечном итоге $a(например "+" & "J" eq "\n").


1
Вы можете сохранить 1 символ, используя chopвместо chomp.
Тото

@ M42: Хороший вопрос, хотя мне скорее нравится надежность текущей версии. Я думаю, что mпока сохраню , это не имеет никакого значения для рейтинга в данный момент. :)
Илмари Каронен

3

T-SQL

SELECT N.number, letter = MIN(SUBSTRING(L.line, N.number, 1))
FROM Lines AS L
INNER JOIN master.dbo.spt_values AS N ON N.type = 'P'
WHERE N.number BETWEEN 1 AND (SELECT MAX(LEN(L2.line)) FROM Lines AS L2)
GROUP BY N.number
HAVING COUNT(DISTINCT SUBSTRING(L.line, N.number, 1)) = 1
ORDER BY N.number

2

Scala 115 107: (−¼ для обработки UTF-8)

io.Source.stdin.getLines.map(_.zipWithIndex).toList.flatten.groupBy(_._2).map(_._2.toSet).filter(_.size==1)

разглазить, а Source.fromFile ("f")не stdinдля лучшей тестируемости

io.Source.fromFile ("f").
  getLines.map (_.zipWithIndex).
    toList.flatten.groupBy (_._2). 
      map (_._2.toSet).
        filter (_.size==1)

Результат:

List(Set((a,0)), Set((g,6)), Set((d,3)))

Спасибо Гарету за сокращение размера 8 за использование stdin.


Вы не можете использовать stdinвместо того, fromFile("f")чтобы сохранить 8 символов?
Гарет

2

VBA ( 307,25 284 - 0,75 бонус = 283,25)

Я знаю, что это уже выиграно, но вот мой выстрел (не чтение файла, просто строка - нужно добавить IO). Мне нравится, что я должен использовать l()рекурсивно. Я обычно не нуждаюсь в рекурсии моего реального программирования. Я только сделал так много тестирования, но я полагаю, что это покрывает условие бонусного балла Unicode. Также предполагается, что vbCrэто терминатор строки. Это может не относиться ко всем системам из-за этого.

Код:

Function a(i)
b=Split(Left(i,Len(i)-1),vbCr):c=UBound(b):For q=1 To Len(b(c)):d=Mid(b(c),q,1):If l(b,c,q,d) Then a=a & q & ": " & d & vbCr:Next
End Function
Function l(m, n, o, p)
If n+1 Then l=IIf(o<=Len(m(n)),Mid(m(n),o,1)=p,0) And l(m,n-1,o,p) Else l=Mid(m(n+1),o,1)=p
End Function

Пример ввода / вывода:

Debug.Print a("abcdefghijklmnop" & vbCr & "abcdefg" & vbCr & "abcabcghijkl" & vbCr)

1: a
2: b
3: c
7: g

2

Q, 32

{a!((*:)x)a:(&)1=(#:')(?:')(+)x}

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

q){a!((*:)x)a:(&)1=(#:')(?:')(+)x}[("abcdefg";"avcddeg";"acbdeeg")]
0| a
3| d
6| g

К, 22

Приведенное выше решение можно уменьшить до 22, записав его полностью на K, а не передавая K-функции интерпретатору Q, уменьшая количество требуемых скобок.

{a!@[*x]a:&1=#:'?:'+x}

1

PHP, 123 127 :(

Я не доволен этим (обязательно будут улучшения), но здесь идет речь:

<?$a=$b=trim(fgets(STDIN));while($l=fgets(STDIN)){$a&=$l;$b|=$l;}$n=-1;while(@$a[++$n]){echo$a[$n]!=$b[$n]?'':"$n:{$a[$n]}\n";}

Доказательство это работает.

Если кто-нибудь может придумать более умный способ инициализации $ a и $ b, пожалуйста, дайте мне знать. Первоначально у меня было $a=$b=$n=''и $ b, в конце концов, было правильно, но [empty] & [anything] == [empty], таким образом, $ a никогда не содержало.


Редактировать: Пришлось исправлять обработку новой строки (+6), но сбросить закрывающий тег (-2).


Мне любопытно, почему вы делаете большинство своих ответов в вики сообщества?
Гарет

Я не хотел об этом. Когда я впервые присоединился к CodeGolf, мне сказали, что это стандартно. Приходится ломать привычку. Может отменить это сейчас, хотя. codegolf.stackexchange.com/a/2249/1419 (см. комментарии)
г-н Лама

Я думаю, что это был стандартный способ сделать что-то на SO для вопросов по коду гольфа, но не здесь, иначе никто бы вообще не имел репутации. :-)
Гарет

Вы можете пометить их и попросить модератора снять их с CW . Просто объясните, что это была ошибка.
Ильмари Каронен

Вы можете сохранить два символа, не используя ?>. Однако я только что заметил, что в вашем коде есть ошибка: он печатает дополнительное совпадение, если все строки содержат завершающий перевод строки, как указано.
Ильмари Каронен

1

JavaScript (125 134 140 )

for(i=s=[];I=s[++i]=prompt(o='');S=I);for(c=-1;w=r=++c<S.length;o+=r?c+':'+C+'\n':'')for(C=S[c];w<i;)r&=s[w++][c]==C;alert(o)

Демо: http://jsfiddle.net/Fv7kY/4/

Изменить 1 : переставить петли, чтобы избежать скобок. Инициализировать с []помощью s. Переместить wприращение в выражение.

Редактировать 2 : установить S=Iзахват последнего введенного слова и сохранить с помощью s[1]. Объединить r=1и ++c<S.length. Установить C=s[c]во внутреннем цикле и сравнить с Cвместо предыдущих и следующих слов, чтобы сократить выражение s[w][c]==s[w++][c]до просто s[w++][c]==C. Всего сохранено 9 символов. Также установите, w=r=...потому что, когда это правда, w=1что нам нужно инициализировать w.


1

Рубин (71)

a,*s=*$<.lines
(a.size-1).times{|i|s.all?{|t|t[i]==a[i]}&&p([i,a[i]])}

выход:

[0, "a"]
[3, "d"]
[6, "g"]

Примечание: похоже, требуется Ruby 1.9; для совместимости t[i]с Ruby 1.8 замените на t[i,1].
Ильмари Каронен

1

Common Lisp, 183 165 символов

(let((l(loop for m =(read-line)until(equal m "")collect m)))(loop for c across(car l)for i from 0 if(null(remove c(mapcar(lambda(y)(char y i))l)))collect(list i c)))

Читаемый формат:

(let ((l (loop for m = (read-line) until (equal m "") collect m)))
  (loop for c across (car l)
        for i from 0 
        if (null (remove c 
                         (mapcar (lambda(y) (char y i))l)))
        collect(list i c)))

Введите это непосредственно в REPL и введите строки, оканчивающиеся пустой строкой.


1

C 126 символов

char a[999],b[999];main(i){for(gets(a);gets(b);)for(i=0;b[i];++i)a[i]^b[i]?a[i]=0:0;
while(i--)a[i]&&printf("%d:%c\n",i,a[i]);}

Я смотрел на это, но я просто не могу уменьшить его. Может понадобиться новый подход.

(Нет бонусных баллов; он обрабатывает строки разного размера, только если первая строка короче.)


0

C # с .NET 4 (280)

using c=System.Console;class P{static void Main(){char[]a=c.ReadLine().ToCharArray();int r,i,l=a.Length;m:i=0;n:r=c.Read();if(r>0&&r!=10&&r!=13){if((int)a[i]!=r)a[i]='\0';i++;goto n;}for(;i>0&&i<l;)a[i++]='\0';if(r>0)goto m;for(i=0;i<l;i++)if(a[i]!='\0')c.WriteLine(i+":"+a[i]);}}
  • 1 строка, 280 символов
  • Включает все необходимые операторы использования и метод Main.
  • Программа не требует пустой строки в конце, но примет ее
  • Пустые строки игнорируются
  • Обрабатывает входные строки любой длины.
  • Зарезервирует вывод до конца (тогда как исходный ответ обеспечил добавочный вывод)

Читаемая версия

    char[]a=c.ReadLine().ToCharArray();
    int r,i,l=a.Length;
    m:
    i=0;
    n:
    r=c.Read();
    if(r>0&&r!=10&&r!=13){
        if((int)a[i]!=r)
            a[i]='\0';
        i++;
        goto n;
    }
    for(;i>0&&i<l;)
        a[i++]='\0';
    if(r>0)
        goto m;
    for(i=0;i<l;i++)
        if(a[i]!='\0')
            c.WriteLine(i+":"+a[i]);

Оригинальный ответ

использование c = System.Console; класс P {static void Main () {char [] a; var b = c.ReadLine (); a = b.ToCharArray (); while (b! = "") {for (int I = 0; я

  • 1 строка
  • 207 персонажей
  • Включает все необходимые операторы использования и метод Main.
  • Программа заканчивается, когда вводится пустая строка.
  • Не обрабатывает входные строки, которые короче первой.


Читаемая версия:

    static void Readable()
    {
        char[]a;
        string b=System.Console.ReadLine();
        a=b.ToCharArray();
        while(b.Length>0)
        {
            for (int i = 0; i < a.Length; i++)
            {
                if (a[i] != b[i])
                {
                    a[i] = '\0';
                }
                else
                {
                    System.Console.WriteLine(i+": "+a[i]);
                }
            }
            b=System.Console.ReadLine();
        }
    }


Когда я запускаю это на тестовом вводе в задании, я получаю 0: a 1: b 2: c 3: d 4: e 5: f 6: g 0: a 2: c 3: d 6: g 0: a 3: d 6: g. Ожидаемый результат будет 0: a 3: d 6: g.
Ильмари Каронен

@Ilmari Хорошо, но он выводит одинаковые столбцы / символы после каждой строки ввода. Если вы вводите файл в качестве стандартного ввода, то вывод может показаться странным, но если вы вводите вручную, я думаю, что это имеет смысл. Я рассмотрю, как рефакторинг, хотя.
Ученик доктора Вилли

Ваше решение дает сбой, если какая-либо строка длиннее первой.
Тимви

@ Тимви Ах ... спасибо, что указал на это!
Ученик доктора Вилли

0

Питон 122 символа :

print("\n".join([str(i)+':'+str(x[0]) for i,x in enumerate(zip(*[tuple(x) for x in input().split()])) if len(set(x))<2]))

вам не нужно пространство между )и for. Так что вместо …str(x[0]) for i,x…, вы можете сделать …str(x[0])for i,x…. Это также подходит к tuple(x) forи.split()])) if
Cyoce

-1

Рубин (242)

s = %w{ abcdefg avcddeg acbdeeg aejdjeggd }
cols = []
s.sort{ |a, b| b.size <=> a.size }[0].size.times do |i|
  uneq=true
  l = s[0][i]
  s.each { |w| uneq = false if l != w[i] }
  cols << [l, i] if uneq
end
cols.each { |c| puts c.join('|') }

Цель задачи состояла в том, чтобы прочитать строки из стандартного ввода. Я готов немного ослабить язык (например, JavaScript в браузере), где эта концепция на самом деле не существует, но у Ruby есть STDIN( ARGFили просто gets).
Илмари Каронен

Ах хорошо. Но если учесть, что STDIN принимает одну строку, то предполагается ли что-то вроде: «Ввести в другой строке или« n »для остановки»? Поэтому создайте цикл для построения массива.
agmcleod

Я добавил некоторые уточнения к вопросу. По сути, вы должны продолжать читать строки ввода до тех пор, пока не достигнете конца файла.
Илмари Каронен

у вас есть тонна ненужных пробелов.
Сайос

-1

C #

List<string> strings = new List<string> { "abcdefg", "avcddeg", "acbdeeg", "aejdjeggd" };
var transposes = from index in Enumerable.Range(0, strings.First().Length)
                 select new string((from s in strings select s[index]).ToArray());
int i = 0;
foreach(string transpose in transposes)
{
   if (transpose.Distinct().Count() == 1)
     Console.WriteLine("{0}: {1}", i , transpose[0]);
   i++;
}

1
Привет, Арджанг, и добро пожаловать в codegolf.SE! Несколько комментариев к вашему ответу: во-первых, поскольку это задача для игры в гольф , вы должны постараться сделать свое решение как можно более коротким; для начала, у вас есть несколько длинных имен переменных, которые вы можете легко сократить до одиночных символов, и некоторые лишние пробелы, которые вы можете удалить. (Можно опубликовать читаемую версию вашего кода вместе с версией «для игры в гольф», но на самом деле вы должны также опубликовать решение для игры в гольф.) Во-вторых, если вы внимательно прочитали вопрос, я указал, что вы должны читать строки из стандартного ввода. , а не кодировать их.
Ильмари Каронен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.