13
\$\begingroup\$

Your task - if you accept it - is to write a program which helps understanding my proposal on meta by calculating the winner of a competition. Of course, answers to this question will be treated as proposed, so your program (if correct) can calculate whether your answer will become the accepted answer.

Rules

  • The program reads a file with multiple lines of the following format (see example below): [Language] TAB [NumberOfCharacters] TAB [LinkToAnswer]
  • The file name is passed as an argument to your program or the file is redirected to standard input of your program. It's your choice, please mention the method when giving the answer
  • It's expected that the input format is correct. There's no need for error handling.
  • The number of characters is positive. Your program must handle lengths up to 65535. 64k should be enough for everybody :-)
  • The program outputs those lines on standard output which meet the idea of the meta proposal, that is
    • the shortest code of a particular programming language wins (reduction phase)
    • the longest code among all programming languages wins (sorting phase)
    • in case of a draw, all answers with the same length shall be printed
  • The order of the output is not important
  • Although the longest code wins, this is not . Your code must be as short as possible for your programming language.
  • Answers on seldom programming languages which are not attempting to shorten the code deserve a downvote, because they try to bypass the intention of this kind of question. If there's only one answer for a specific programming language, it would be considered as a winner candidate, so you could start blowing its code.

Example input file (separated by single tabs if there should be an issue with formatting):

GolfScript  34  http://short.url/answer/ags
GolfScript  42  http://short.url/answer/gsq
C#  210 http://short.url/answer/cs2
Java    208 http://short.url/answer/jav
C#  208 http://short.url/answer/poi
J   23  http://short.url/answer/jsh
Ruby    67  http://short.url/answer/rub
C#  208 http://short.url/answer/yac
GolfScript  210 http://short.url/answer/210

Expected output (order is not important):

C#  208 http://short.url/answer/poi
C#  208 http://short.url/answer/yac
Java    208 http://short.url/answer/jav

Update

Some programs rely on the fact that there is a single maximum (like the C# 210 character program). Derived from reality, someone can also write a GolfScript program with 210 characters. The output would remain the same. I have added such a GolfScript to the input.

Update 2

As suggested I have retagged (still code-golf as well) and the deadline is 2014-03-06 (which looks like an arbitrary date, but I'll be back to Germany from travelling then).

Final results

I decided to vote like the following:

  • Answers where the number of characters cannot be confirmed get a comment to explain the count.
  • Answers which can easily be reduced get a comment, an edit suggestion and go into the result with the lower count value. (Hopefully I have seen that in advance).
  • Answers which do not compile get a downvote. (Quite a hard task as it turns out).
  • Answers which are not golfed get a downvote (as described in the rules already).
  • Answers which produce expected output get an upvote. Due to some answers which do not work as expected, I use 4 different input files and check against the expected result.

Finally, the winner is determined by providing the qualifying answers table as input to my reference program (plus double checking the result manually). If my own answer would be the winning one, I'd exclude it from the list. In case of several winners, I would have to pick only one. Therefore, some bonuses can be earned:

  • answers which accept more input than expected (e.g. outside the defined ranges)
  • answers which use a clever idea of making it short

I have taken a snapshot of the answers on 6th of March 2014, 19:45 UTC+1. The analysis is ongoing. Checking all the answers is harder than expected...

\$\endgroup\$
2
  • \$\begingroup\$ Shouldn't this be tagged code-challenge for now? Also when is deadline? \$\endgroup\$ Feb 26, 2014 at 10:01
  • 2
    \$\begingroup\$ Alt-name for this is Code-Blackjack \$\endgroup\$ Feb 26, 2014 at 17:02

9 Answers 9

2
\$\begingroup\$

Java - 556

import java.util.*;class G{public static void main(String[]x){TreeMap<?,TreeMap>m=new TreeMap();try{Scanner s=new Scanner(System.in);for(;;){String[]a=s.nextLine().split("\t");a(new Long(a[1]),a(a[0],m)).put(a[2],a);}}catch(Exception e){}TreeMap<?,Map<?,String[]>>n=new TreeMap();for(TreeMap o:m.values())a(o.firstEntry().getKey(),n).putAll((Map)o.firstEntry().getValue());for(String[]o:n.lastEntry().getValue().values())System.out.println(o[0]+"\t"+o[1]+"\t"+o[2]);}static<T>Map a(T t,Map m){if(m.get(t)==null)m.put(t,new TreeMap());return(Map)m.get(t);}}

Program will read from STDIN.

import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;

class G {
    public static void main(String[] x) {
        TreeMap<?, TreeMap> m = new TreeMap();
        try {
            Scanner s = new Scanner(System.in);
            for (; ; ) {
                String[] a = s.nextLine().split("\t");
                a(new Long(a[1]), a(a[0], m)).put(a[2], a);
            }
        } catch (Exception e) {
        }
        TreeMap<?, Map<?, String[]>> n = new TreeMap();
        for (TreeMap o : m.values())
            a(o.firstEntry().getKey(), n).putAll((Map) o.firstEntry().getValue());
        for (String[] o : n.lastEntry().getValue().values())
            System.out.println(o[0] + "\t" + o[1] + "\t" + o[2]);
    }

    static <T> Map a(T t, Map m) {
        if (m.get(t) == null)
            m.put(t, new TreeMap());
        return (Map) m.get(t);
    }
}
  1. Programm will read line by line until an exception occours (either ArrayIndexOutOfBoundsException when a blank line is encountered or NoSuchElementException if input ends without trailing new line). Each line read is added to the TreeMap m, which could have been defined as TreeMap<String, TreeMap<Long, TreeMap<String,String[]>>> (left-to-right: language, code-size, URL, input).
  2. Then a result-TreeSet<Long, TreeSet<String, String[]>> n (left-to-right: code-size, URL, input) is build where the contents of every languages firstEntry() are aggregated.
  3. lastEntry() of the aggregated TreeMap contains our result - we only need to print it.

Try on ideone.com (switched last two lines of input to show that all lines are read)

\$\endgroup\$
4
  • \$\begingroup\$ Had to add an variable to store BufferedReader -.- \$\endgroup\$ Feb 23, 2014 at 19:39
  • 1
    \$\begingroup\$ Maybe Java wins this time, because it doesn't have a var keyword... \$\endgroup\$ Feb 24, 2014 at 1:22
  • \$\begingroup\$ @ThomasW. just realized I left some unnecessary {} inside the golfed version -.- \$\endgroup\$ Mar 7, 2014 at 14:41
  • \$\begingroup\$ Also just relaized I was using Integer. While int is shorter than long, Integer shurely should be golfed to Long -.- \$\endgroup\$ Mar 7, 2014 at 14:52
2
\$\begingroup\$

Perl, 195 bytes

while(<>){/(\S+)\t(\d+)\t(.+)/;push@{$a{$1}},$3if$2==$l{$1};$l{$1}=$2,$a{$1}=[$3]if $2<($l{$1}//65536)}$m=(sort{$b<=>$a}values%l)[0];map{$l=$_;map{print"$l\t$m\t$_\n"if$l{$l}==$m}@{$a{$l}}}keys%l

Input is expected in STDIN, result is written to STDOUT:

C#      208     http://short.url/answer/poi
C#      208     http://short.url/answer/yac
Java    208     http://short.url/answer/jav

Ungolfed version

#!/usr/bin/env perl
use strict;
$^W=1;

# hash %language remembers the minimum count for a language
# %language: <language> => <minimum count>
my %language;
# hash %array remembers the URLs for the minimum count of the language
# %array: <language> => [<url>, <url>, ....]
my %array;

while(<>){
    # parse input line (no error checking)
    /(\S+)\t(\d+)\t(.+)/;
    my ($lang, $count, $url) = ($1, $2, $3);
    # add URL, if the count is the current minimum for the language
    if ($count == ($language{$lang}//0)) {
    # better, but longer version:
    # if (defined $language{$lang} and $count == $language{$lang}) {
        push @{$array{$lang}}, $url;
    }
    # create a new entry for the language, if there is a new minimum
    if ($count < ($language{$lang}//65536)) {
    # better, but longer version:
    # if (not defined $language{$lang} or $count < $language{$lang}) {
        $language{$lang} = $count;
        $array{$lang} = [$url];   
    }
}

# Sort the minimal values in numerical descending order and
# get the first entry as maximum.
my $maximum = (sort { $b <=> $a } values %language)[0];

# Loop over all URLs of minimal answers for the language,
# but print only the entries for the languages with the largest
# minima.
foreach my $lang (keys %language) {
    foreach my $url (@{$array{$lang}}) {
        if ($language{$lang} == $maximum) {
            print "$lang\t$maximum\t$url\n";
        }
    }
}
__END__
\$\endgroup\$
2
  • \$\begingroup\$ Heiko, as @grovesNL pointed out, some programs might rely on the fact that there is a single maximum. Maybe you can check whether your program is affected. Just add a GolfScript 210 http://short.url/answer/210 line to the input and see if the output remains the same. Actually I think yours is not affected, because you're using [0] for the maximum, but I don't have Perl available at the moment to give it a try. \$\endgroup\$ Feb 24, 2014 at 1:31
  • \$\begingroup\$ @ThomasW.: It is not affected. I have added the line and the output remains the same. After the first part that reads the file, data structure %l/%language contains the languages and their minimal values. Data structure %a/%array contains only those language/URL pairs, whose value is the minimum for this language. Then the minimum values are sorted in descending order and the first one is uses as global maximum and as filter condition for %a/%array. \$\endgroup\$ Feb 24, 2014 at 1:49
2
\$\begingroup\$

dg - 286 281 260 251 218 bytes

import '/sys'
d=dict!
for(a,b,c)in(map str.split$(sys.stdin.read!).splitlines!)=>d!!a=(d.get a list!)+(list'(int b,c))
for(i,l)in(d.items!)=>for(s,u)in l=>s==(max$map(i->fst$min i)d.values!)=>print$i+' '+(str s)+' '+u

Example:

$ cat langs.txt | dg langs.dg 
C# 208 http://short.url/answer/poi
C# 208 http://short.url/answer/yac
Java 208 http://short.url/answer/jav

Ungolfed version:

import '/sys'

s = sys.stdin.read!
d = dict!
# convert the string into a list of tuples (name, score, url)
u = map str.split $ s.splitlines!
# add all the values to the dict (converting the score to an integer)
for (a, b, c) in u =>
  d!!a = (d.get a list!) + (list' (int b, c))
# computes the maximum value amongst the mins
m = max $ map (i -> fst $ min i) d.values!
for (i, l) in (d.items!) =>
  for (s, u) in l =>
    # if the score equals the maximum then print all the line
    s == m => print $ i + ' ' + (str s) + ' ' + u  # actually here .format()
                                                   # would be better

Q: What the heck is dg?
A: A programming language that compiles to CPython bytecode, much like Scala compiles to JVM's. That essentially means that dg is an alternative syntax for Python 3. It allows you to use all of the existing libraries, too.

More info here (even a tutorial!): https://pyos.github.io/dg

\$\endgroup\$
4
  • \$\begingroup\$ If I put that into a file, it has only 217 bytes (Linux line endings) \$\endgroup\$ Mar 6, 2014 at 19:26
  • \$\begingroup\$ @ThomasW. Weird! Using cat langs.dg | wc -c I get 218! \$\endgroup\$
    – rubik
    Mar 6, 2014 at 20:36
  • \$\begingroup\$ Maybe trailing newline vs. no trailing newline? \$\endgroup\$ Mar 7, 2014 at 22:37
  • \$\begingroup\$ @TheConstructor it could be, although it shouldn't save it with a newline oO \$\endgroup\$
    – rubik
    Mar 8, 2014 at 11:47
2
\$\begingroup\$

Python 378 377 372

import sys
d=__import__("collections").defaultdict(list)
o={}
x=int
n="\n"
for i,l,u in[a.split()for a in sys.stdin.read().strip().split(n)]:d[i]+=[(l,u)]
for e,b in d.items():o[e]=[i for i in b if i[0]==str(min([x(i[0])for i in b]))]
print("".join(n.join("\t".join([u,s[0],s[1]])for s in y if x(s[0])==max(x(i[0][0])for i in o.values()))+n for u,y in o.items()).strip())

Input on the stdin:

C:\Users\gcq\Documents\python>type m.txt | python test.py
C#      208     http://short.url/answer/poi
C#      208     http://short.url/answer/yac
Java    208     http://short.url/answer/jav

And this is what i had before starting to compress it down, at 551 chars:

from collections import defaultdict
import sys
d = defaultdict(list)

for language, length, url in [a.split() for a in sys.stdin.read().strip().split("\n")]:
    d[language].append((length, url))

o = {}
for language, data in d.items():
    winval = data[0][0]
    for i in data:
        if int(i[0]) < int(winval):
            winval = i[0]
    o[language] = [i for i in data if i[0] == winval]

maxlen = max(int(i[0][0]) for i in o.values())

for language, dataa in o.items():
    for data in dataa:
        if int(data[0]) == maxlen:
            print("\t".join([language, data[0], data[1]]))
\$\endgroup\$
1
\$\begingroup\$

C# - 628

Here's a longer alternative of yours that uses DataTable:

using Microsoft.VisualBasic.FileIO;namespace System{using T=Data.DataTable;using R=Data.DataRow;using V=Data.DataView;using C=Data.DataColumn;class p{static void Main(string[] a){var I=typeof(Int32);T t=new T();t.Columns.AddRange(new[]{new C("a"),new C("b",I),new C("c"),new C("d",I)});var f=new TextFieldParser(a[0]);f.SetDelimiters("\t");while(!f.EndOfData){var r=t.NewRow();r.ItemArray=f.ReadFields();t.Rows.Add(r);}foreach(R r in t.Rows){r[3]=t.Compute("min(b)","a='"+r[0]+"'");}V v=new V(t);T s=v.ToTable();foreach(R r in s.Select("b='"+t.Compute("max(d)","")+"'")){Console.WriteLine(String.Join("\t",r[0],r[1],r[2]));}}}}

I originally thought I may have gained slight code reduction from using max/min with DataTable, but the types required to build the DataTable (rows/columns/view) add a lot of length, unfortunately. I'm new to code golfing so maybe somebody would be able to reduce it further. Still a fun challenge.

\$\endgroup\$
1
\$\begingroup\$

Rebol - 314

d: map[]foreach r read/lines to-file system/script/args[r: split r tab p: take r r/1: to-integer r/1 r/2: reduce[r/2]either none? d/:p[repend d[p r]][case[d/:p/1 > r/1[d/:p: r]d/:p/1 = r/1[append d/:p/2 r/2]]]]l: 0 foreach[k v]d[l: max l v/1]foreach[k v]d[if l = v/1[foreach n v/2[print rejoin[k tab v/1 tab n]]]]

un-golfed

d: map []

foreach r read/lines to-file system/script/args [
    r: split r tab
    p: take r
    r/1: to-integer r/1
    r/2: reduce [r/2]
    either none? d/:p [repend d [p r]] [
        case [
            d/:p/1 > r/1 [d/:p: r]
            d/:p/1 = r/1 [append d/:p/2 r/2]
        ]
    ]
]

l: 0 foreach [k v] d [l: max l v/1]
foreach [k v] d [
    if l = v/1 [
        foreach n v/2 [print rejoin [k tab v/1 tab n]]
    ]
]

Usage example:

$ rebol script.reb data.txt
C#    208   http://short.url/answer/poi
C#    208   http://short.url/answer/yac
Java  208   http://short.url/answer/jav
\$\endgroup\$
0
\$\begingroup\$

C# - 515

Expects a file name as argument

using System.Collections.Generic;namespace N{using S=SortedList<int,T>;class T:List<string>{static void Main(string[]a){var d=new Dictionary<string,S>();int n,m=0;T w=new T();foreach(var l in System.IO.File.ReadAllLines(a[0])){var p=(a=l.Split('\t'))[0];n=int.Parse(a[1]);if(!d.ContainsKey(p))d.Add(p,new S());if(!d[p].ContainsKey(n))d[p].Add(n,new T());d[p][n].Add(l);}foreach(var e in d){n=e.Value.Keys[0];if(n==m)w.AddRange(e.Value[n]);if(n>m)w=e.Value[m=n];}foreach(var e in w)System.Console.WriteLine(e);}}}

First I designed my C# program to be straight forward, because I wanted to have a kind of reference program. But then I decided to also jump into contest myself and golfed it. This is one of the earlier versions of the code + some comments:

// N: namespace
// P: Program
// S: type definition: sorted dictionary
// a: arguments
// d: data container
// r: lines read from text file
// l: single line from r
// t: tabbed part of l after splitting
// p: programming language name
// n: character count
// m: maximum character count
// w: list of winners
// e: entry in data container
// c: winner candidate
using System.Collections.Generic;
namespace N
{
    using S = SortedList<int, P>;
    public class P : List<string>
    {
        public static void Main(string[] a)
        {
            var r = System.IO.File.ReadAllLines(a[0]);
            // Make it a data structure
            var d = new Dictionary<string, S>();
            foreach (var l in r)
            {
                var t = l.Split('\t');
                var p = t[0];
                var n = int.Parse(t[1]);
                if (!d.ContainsKey(p)) d.Add(p, new S());
                if (!d[p].ContainsKey(n)) d[p].Add(n, new P());
                d[p][n].Add(l);
            }
            // Get the maximum values
            var m = 0;
            P w = null;
            foreach (var e in d)
            {
                foreach (var s in e.Value.Keys)
                {
                    if (s > m)
                    {
                        w = e.Value[s];
                        m = s;
                    }
                    else if (s == m)
                    {
                        w.AddRange(e.Value[s]);
                    }
                    break; // Break here to get the shortest solution per language
                }
            }
            // Print everything on console
            foreach (var e in w)
            {
                System.Console.WriteLine(e);
            }
        }
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ It seems 515 file size on my disk included a byte order mark. Copy/paste from here is only 512 bytes. \$\endgroup\$ Mar 6, 2014 at 19:37
0
\$\begingroup\$

C# - 460 359

After realizing how bulky my DataTable solution was, I created the following example using Linq. It uses the same methodology as my previous solution.

Golfed

namespace System{using Linq;using IO;class p{static void Main(string[]i){var l=(from f in File.ReadAllLines(i[0])let s=f.Split('\t')select new Tuple<string,int,string>(s[0],Convert.ToInt16(s[1]),f)).ToList();foreach(var f in l.Where(a=>a.Item2==l.Where(b=>b.Item1==l.Single(c=>c.Item2==l.Max(d=>d.Item2)).Item1).Min(e=>e.Item2)))Console.WriteLine(f.Item3);}}}

Ungolfed

namespace System
{
    using Linq;
    using IO;
    class p
    {
        static void Main(string[]i)
        {
            var l=(from f in File.ReadAllLines(i[0])
                   let s=f.Split('\t')
                   select new Tuple<string, int, string>(s[0],Convert.ToInt16(s[1]),f)).ToList();
            foreach(var f in l.
                Where(a=>a.Item2==l.
                    Where(b=>b.Item1==l.
                        Single(c=>c.Item2==l.
                            Max(d=>d.Item2)).Item1).
                                Min(e=>e.Item2)))
            Console.WriteLine(f.Item3);
        }
    }
}

I'm still fairly new to Linq so I'm almost positive those expressions can be reduced further.

From your question, it's not clear if there is a single maximum length solution. For my answers I've used the assumption that there is a single maximum point (ie. if there was a GolfScript maximum of 210 as well, it may fail based on the Single maximum record returned). Heiko's solution would have the same issue. To fix this, we would have to add another step that contained a list of tied maxima to check minima for each language.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ It seems to me that you could save f as Item3 (instead of s[2]) and then write f.Item3 to the Console without the need to recombine Item1 and Item2. \$\endgroup\$ Feb 23, 2014 at 11:34
  • \$\begingroup\$ Thanks for the clarification of the requirements. Derived from reality I would say it could happen that someone (unexperienced, obviously) writes a GolfScript with 210 characters. \$\endgroup\$ Feb 23, 2014 at 12:13
  • 1
    \$\begingroup\$ If you convert the first foreach-loop to LINQ, it becomes even shorter: namespace System{using Linq;using IO;class p{static void Main(string[]i){var l=(from f in File.ReadAllLines(i[0])let s=f.Split('\t') select new Tuple<string, int, string>(s[0],Convert.ToInt16(s[1]),f)).ToList();foreach(var f in l.Where(a=>a.Item2==l.Where(b=>b.Item1==l.Single(c=>c.Item2==l.Max(d=>d.Item2)).Item1).Min(e=>e.Item2)))Console.WriteLine(f.Item3);}}} \$\endgroup\$ Feb 23, 2014 at 12:33
  • \$\begingroup\$ @ThomasW.: Good idea for the split. Thanks for the foreach loop conversion, I had thought about it adding that originally but I didn't know I could use let that way. \$\endgroup\$
    – grovesNL
    Feb 23, 2014 at 14:52
  • \$\begingroup\$ I think I begin to understand what your query does :) and it will also fail for simpler input like this: Golfscript 100 ..., C# 1 ..., C# 200 .... This probably needs some rework \$\endgroup\$ Feb 25, 2014 at 14:08
0
\$\begingroup\$

C++ - 535

Will only output the answers tied for longest position after selecting only the shortest answers of each language as potential winners.

#include<fstream>
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main(){

    string s;
    vector<string>l;
    vector<int>v;
    vector<string>u;
    cin>>s;
    
    ifstream i(s.c_str());
    
    do{
        int n;
        i>>s;
        if(i.eof())break;
        l.push_back(s);
        i>>n;
        v.push_back(n);
        i>>s;
        u.push_back(s);
    }while(1);

    for(int i=0;i<l.size();i++){
        for(int j=0;j<l.size();j++){
            if(l[j]==l[i]){
                if(v[i]>v[j])l[i]="";
                else if(v[i]<v[j])l[j]="";
            }
        }
    }
    int n=0;
    for(int i=0;i<v.size();i++)
        if(n<v[i]&l[i]!="")n=v[i];

    for(int i=0;i<v.size();i++)
        if(v[i]==n)cout<<l[i]<<'\t'<<v[i]<<'\t'<<u[i]<<endl;
}

Golfed (not as unreadable as some languages):

#include<fstream>
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main(){string s;vector<string>l;vector<int>v;vector<string>u;cin>>s;ifstream i(s.c_str());do{int n;i>>s;if(i.eof())break;l.push_back(s);i>>n;v.push_back(n);i>>s;u.push_back(s);}while(1);for(int i=0;i<l.size();i++)for(int j=0;j<l.size();j++)if(l[j]==l[i]){if(v[i]>v[j])l[i]="";else if(v[i]<v[j])l[j]="";}int n=0;for(int i=0;i<v.size();i++)if(n<v[i]&l[i]!="")n=v[i];for(int i=0;i<v.size();i++)if(v[i]==n)cout<<l[i]<<'\t'<<v[i]<<'\t'<<u[i]<<endl;}
\$\endgroup\$
11
  • \$\begingroup\$ Have you checked your output against the expected output? With 8 lines of input, it shall give only 3 lines as output. Your program seems to output everything. \$\endgroup\$ Feb 24, 2014 at 1:19
  • \$\begingroup\$ @ThomasW. Oh, I misunderstood that part. I will remove it for now. \$\endgroup\$
    – user10766
    Feb 24, 2014 at 1:33
  • \$\begingroup\$ @ThomasW. Does this look right? \$\endgroup\$
    – user10766
    Feb 24, 2014 at 2:18
  • \$\begingroup\$ If I put that into a file I get 540 bytes, not 535. Could you double check the length, please? \$\endgroup\$ Mar 6, 2014 at 19:33
  • \$\begingroup\$ It is 535 characters. We are both correct. I can change it if you want. \$\endgroup\$
    – user10766
    Mar 6, 2014 at 19:51

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