查找所有字符都相同的列


18

在SO上遇到了这个问题,并认为这将是一个不错的高尔夫挑战。所以这里是:

挑战:

编写一个程序,该程序读取一系列字符串,每行一个,并输出每个字符串具有相同字符的所有位置的列表。

输入和输出:

输入由一行或多行可打印的非空白ASCII字符组成,每行后跟一个换行符。您可以假定所有输入线都具有相同的长度。换行符不应被视为输入的一部分(即,您不应将其作为匹配字符输出)。

输入示例(从SO问题中偷偷偷走的):

abcdefg
avcddeg
acbdeeg

读取输入后,程序应打印每个匹配列的位置及其包含的字符。(如果您的程序可以尽早确定没有匹配的列,则可以但不必停止读取其他输入。)允许使用任何合理的输出格式;特别是,您可以对位置使用基于0或基于1的索引。

上述输入的示例输出(使用基于0的索引):

0: a
3: d
6: g

得分:

这是代码高尔夫,所以最短的答案会获胜。如果出现平局,则可能会授予部分平局决胜字符以提供其他功能:

  • −½个字符,用于正确处理长度不等的输入行。(输出中不应包含最短输入行的末尾位置。)
  • −¼个字符,用于正确处理由任意UTF-8编码的Unicode字符组成的输入。

为了获得启发,您可能会在SO问题上找到一些解决方案(见上文)。

说明:

  • 简单地串联的位置和角色,如0a3d6g,并不能算作“合理的输出”。您应该在输出的每个元素之间提供某种分隔符(例如空格),以便可以对其进行明确的解析。

  • 输入将在标准输入流(stdin)上提供,或使用您选择的语言最自然的任何文本文件输入机制提供。(如果你选择的语言不具有对文件输入一个自然机制,尽一切似乎在精神上最接近的一次。)

  • 当没有更多数据要读取时(即发生文件结束条件时),输入结束。如果需要,可以要求输入以空行终止(显然,您不应将其视为输入的一部分)。如果这样做,请在回答中提及它,以便其他人可以提供正确的测试输入。

  • 每行输入,包括最后一行,都以换行符结尾。您的答案不得将此换行符报告为匹配列。(如果您的解决方案还可以处理最后一行不以换行符结尾的输入,那是很好的,但这不是必需的。)


那么空行会终止输入吗?
史蒂芬·鲁姆巴尔斯基

“您应该在输出的每个元素之间提供某种分隔符,以便可以明确地对其进行解析。” 空格算作分隔符吗?
Steven Rumbalski 2012年

@StevenRumbalski:当没有更多数据可读取时,输入结束;如果您的语言无法检测到EOF,我想我可以在行末尾添加空白行。是的,空格是一个很好的分隔符。
Ilmari Karonen 2012年

我们可以有一些任意UTF-8编码的Unicode字符示例代码吗?
用户未知

Answers:


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等于右参数的形状/长度(),则返回空集()。
    • 分隔函数中的两个表达式。如果前一个表达式未得到求值(因此未返回任何内容),则移至下一个表达式。
    • 我们使用自引用函数()递归调用该函数。该函数的参数是一行未评估的用户输入,由quote-quad()给出。
    • ⊂⍵,⍨¨⍳⍴⍵ 为字符串中的每个字符创建对,其中每个对的第一个元素是其在字符串中的位置,其第二个元素是字符。
    • ⍳⍴⍵给出一个从1到的向量⍴⍵,或者输入字符串的长度。
    • ⍵,⍨¨将换位后的串联函数(,⍨)应用于¨左侧的每个()元素(在本例中为用户输入)和右侧。对串联函数进行通勤会导致其左参数和右参数被交换。
    • 最后,我们使用将结果括起来,以便区分输入行。
  • 最初,我们使用用户输入()来提供函数。
  • 最后,我们/使用交集函数()缩小()对向量的结果向量,得出在所有子向量中都可以找到的对。

每当我看到我没有J或GolfScript的APL时,我就不会有内在的负面回应。但是无论如何+1都是一个很好的解决方案。
史蒂芬·鲁姆巴尔斯基

实际上,我一直在考虑切换到J ...我会在原因列表中加以说明。:)
Dillon Cower 2012年

12

Golfscript(28个字符)

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

传递Unicode时存在字符集问题,因此没有四分之一的奖金。


1
+1。投票数不应少于我的答案。
Steven Rumbalski 2012年

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.更好
史蒂芬Rumbalski

投票数不应少于我的答案。
Steven Rumbalski 2012年

1
@StevenRumbalski投票并不总是反映代码的相对大小。有时它成为语言普及竞赛。我同意,golfscript答案应该与APL一起使用,不幸的是,我已经给了我赞成,并且不能帮助进一步提高它。
Gareth 2012年

8

Haskell,64个字符

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

处理长度不等的行。Unicode支持取决于当前的语言环境设置。

输出示例:

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

+1。投票数不应少于我的答案。
Steven Rumbalski 2012年

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高尔夫球场,但您可以输掉整整四个字符: [:-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')]。我看不出有办法避免剥离最后一行的换行符。如果我误会了,请纠正我。谢谢您的支持。
史蒂文·鲁姆巴尔斯基

如果您删除数据文件中的最后一个换行符,则该行的元组将不完整(缺少一个“ \ n”,因此zip仅考虑并返回我们要查找的数据,从而允许删除[:-1].egzip([1,2,3,4],[1,2,3])=> [(1, 1), (2, 2), (3, 3)]
ChristopheD

@ChristopheD:根据规范,“输入由[...]行组成,每行后都有换行符。”
Ilmari Karonen 2012年

1
拒绝这个答案的人会解释为什么吗?
史蒂文·鲁姆巴尔斯基

5

(Bash)Shell脚本,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 2012年

@Ilmari Karonen:这是在Mac(雪豹,10.6.2)上测试过的,但应该可以在其他地方使用。我想明天将它在Linux上修复(应该是一个小的修复)
ChristopheD

2
ormaaj缺少代表,但想发表评论:由于Il[ ; 之后缺少空格,它对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线程解决方案的简化版本:

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

与SO版本不同,此版本使用基于1的索引作为输出。它使用Perl 5.10 say功能,因此需要与perl -M5.010(或与perl -E)一起运行。

与SO版本一样,此代码处理可变长度的行,并且如果标准输入和输出处于UTF-8模式,则可以处理任意Unicode输入。las,默认情况下不是,除非指定了非自由的 -CS命令行开关。因此,它获得-½字符加值,而不是-¼字符加值。

编辑: +1字符以修复错误:仅仅因为输入字符串不包含换行符并不意味着它们不能以$a(例如"+" & "J" eq "\n")结尾。


1
您可以使用chop代替来保存1个字符chomp
Toto 2012年

@ M42:好点,尽管我更喜欢当前版本的健壮性。我想我m现在会保留,这并不意味着它目前对排名没有任何影响。:)
Ilmari Karonen 2012年

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

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)))

感谢Gareth减少了使用8号的大小stdin


您不能使用stdin而不是fromFile("f")保存8个字符吗?
Gareth 2012年

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

问32

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

用法

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

K,22

通过将其完全用K编写而不是将K函数传递给Q解释器,可以将上述解决方案简化为22,从而减少了所需的括号数量。

{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)。


我很好奇,您为什么要把大部分答案用于社区维基?
Gareth 2012年

我不是故意要这么做的。很久以前,当我第一次加入CodeGolf时,有人告诉我这是标准的。必须打破习惯。现在可以取消Wiki。 codegolf.stackexchange.com/a/2249/1419(请参阅评论)
Llama先生

我认为这是在SO上解决高尔夫球问题的标准方法,但是在这里不是这样,否则没人会赢得任何声誉。:-)
Gareth 2012年

您可能会标记它们,并要求主持人取消CW。请解释一下这是一个错误。
Ilmari Karonen 2012年

您可以省去两个字符?>。但是,我只是注意到您的代码有一个错误:如果所有行都包含指定的尾随换行符,它将打印一个额外的匹配项。
Ilmari Karonen 2012年

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:重新排列循环,以避免大括号。初始化i与[]结合s。将w增量移动到表达式中。

编辑2:设置S=I为捕获最后输入的单词并使用保存s[1]。合并r=1++c<S.length。设置C=s[c]在内部循环中,并与C而不是前一个和下一个单词进行比较,以将表达式缩短s[w][c]==s[w++][c]为just 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;为了与Ruby 1.8兼容,请替换t[i]t[i,1]
Ilmari Karonen 2012年

1

Common Lisp,183165个字符

(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

带有.NET 4的C#(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个字符
  • 包括所有必要的using语句和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; class P {static void Main(){char [] a; var b = c.ReadLine(); a = b.ToCharArray(); while(b!=“”){for(int i = 0; i

  • 1线
  • 207个字符
  • 包括所有必要的using语句和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 Karonen 2012年

@Ilmari好的,但是它在每行输入之后输出相同的列/字符。如果您将文件作为标准输入,那么输出可能看起来很奇怪,但是如果您手动输入,我认为这是有道理的。不过,我将考虑如何重构。
Wily博士的学徒

如果任何行比第一行长,您的解决方案就会崩溃。
Timwi

@Timwi啊...感谢指出!
Wily博士的学徒,2012年

0

python 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确实有STDINARGF或只是简单地gets)。
Ilmari Karonen 2012年

啊好吧。但是考虑到STDIN接受一行,是否假设类似:“输入另一行,或者'n'停止”?因此,创建一个循环来构建数组。
agmcleod

我对这个问题做了一些澄清。基本上,您应该继续读取输入行,直到到达文件末尾。
Ilmari Karonen 2012年

您有大量不必要的空白。
Cyoce '16

-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!关于您的答案的几点评论:首先,由于这是一个代码高尔夫挑战,因此您应该尝试使解决方案尽可能简短。刚开始时,您有一些很长的变量名,可以很容易地缩短为单个字符,还有一些多余的空格可以删除。(将代码的可读版本与“ golfed”代码一起发布是很好的,但是实际上您也应该发布golfed解决方案。)其次,如果您仔细阅读了问题,我指定您应该从标准输入中读取字符串,而不是对其进行硬编码。
Ilmari Karonen 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.