Golf Down the PPCG Usernames

JavaScript (ES6) 159

Following the specs and not the example.

I generate the candidate nicknames having a current middle word (at the beginning, the first word). The words before the current are used 'as is'. The words after the current contribute with no - or just the first - character. The current word contributes with 1 more character for each loop.

Example 'Just Some Name' => 'Just','Some','Name'
Cw Just, position 1, try J, JS, JSN
Cw Just, position 2, try Ju, JuS, JuSN
Cw Just, position 3, try Jus, JusS, JusSN
Cw Just, position 4, try Just, JustS, JustSN
Now Just is exhausted, Some becomes Cw, position restarted to 2 (for position 1, all already tried)

Cw Some, position 2, try Just, JustSo, JustSoN
Cw Some, position 3, try Just, JustSom, JustSomN
Cw Some, position 4, try Just, JustSome, JustSomeN
Now Some is exhausted, Name becomes Cw, position restarted to 2

Cw Name, position 2, try Just, JustSome, JustSomeNa
Cw Name, position 3, try Just, JustSome, JustSomeNam
Cw Name, position 4, try Just, JustSome, JustSomeName
That's all folks!

The code

(q is current word position, p is slicing position)

F=l=>
  l.map(w=>{ 
    for(w=w.match(/[^ ]+/g),q=p=0;
        w.every((w,i)=>~o.indexOf(t+=i<q?w:i>q?w[0]:w.slice(0,p+1)),t='')
        &&(w[q][p++]||(p=1,w[++q]));
       );
    o.push(t)
  },o=[])&&o

Test In Firefox/FireBug console

F(['Martin Buttner','Doorknob','Peter Taylor','Howard','marinus'
  ,'Dennis','DigitalTrauma','David Carraher'
  ,'Martin Bitter','Martin Butter','Martin Battle','Martini Beer','Mart Beer'])

["M", "D", "P", "H", "m", "De", "Di", "DC", "MB", "Ma", "MaB", "Mar", "MarB"]


CJam, 58 53 bytes

This can be golfed a lot.. But for starters:

LqN/{:Q1<aQ,,:)QS/f{{1$<_,@-z1e>}%W<s}+{a1$&!}=a+}/N*

Code Expansion:

L                         "Put an empty array on stack. This is the final nickname array";
 qN/{  ...   }/           "Read the input and split it on new lines. Run the block for each";
     :Q1<a                "Store each name in Q and get its first char. Wrap it in an array";
          Q,,:)           "Get an array of 1 to length(name) integers";
               QS/        "Split the name on spaces";
f{{           }%   }      "for each of the integer in the array, run the code block";
                          "and then for each of the name part, run the inner code block";
   1$<                    "Copy the integer, take first that many characters from the";
                          "first part of the name";
      _,@-z1e>            "Get the actual length of the part and the number of characters";
                          "to be taken from the next name part, minimum being 1";
                W<        "Get rid of the last integer which equals 1";
                  s       "Concat all name parts in the array";
                    +     "Add the list of nick names as per spec with the first character";
{     }=                  "Get the first nick name that matches the criteria";
 a1$&                     "Wrap the nick name in an array and do set intersection with";
                          "the copy of existing nick names";
     !                    "Choose this nick name if the intersection is empty";
N*                        "After the { ... }/ for loop, the stack contains the final";
                          "nick names array. Print it separated with new lines";

Try it online here


PHP, 327 289 275 274 270

There may still be a little golfing potential.

while($n=fgets(STDIN)){$c=count($w=preg_split('/\s+/',trim($n)));$p=[];for($k=0;$k<$c;$p[$k]++){for($t='',$j=0;$j<$c;$j++)$t.=substr($w[$j],0,$p[$j]+1);for($j=1;$j<=strlen($t);$j++)if(!in_array($v=substr($t,0,$j),$u))break 2;$k+=$p[$k]==strlen($w[$k]);}echo$u[]=$v,'
';}
  • Program operates on stdin/stdout, works on ASCII, buggy on UTF
  • usage: php -d error_reporting=0 golfnicks.php < nicknames.txt
  • or cat <<EOF | php -d error_reporting=0 golfnicks.php + list of names + EOF
  • To test as function in web browser: fetch the breakdown, uncomment all lines marked with // FUNC and comment the one marked with //PROG. Try f(array_fill(0,21,'Just Some Name'));

breakdown

#error_reporting(0);function f($a){echo'<pre>'; // FUNC
#foreach($a as$n) // FUNC
while($n=fgets(STDIN)) // PROG
{
    $c=count($w=preg_split('/\s+/',trim($n)));     // split name to words, count them
    $p=[];                                         // initialize cursors
    for($k=0;$k<$c;$p[$k]++)
    {
        for($t='',$j=0;$j<$c;$j++)$t.=substr($w[$j],0,$p[$j]+1); // concatenate prefixes
        for($j=1;$j<=strlen($t);$j++)              // loop through possible nicks
            if(!in_array($v=substr($t,0,$j),$u))   // unused nick found
                break 2;                           // -> break cursor loop
        $k+=$p[$k]==strlen($w[$k]);                // if Cw exhausted -> next word
        // strlen()-1 would be correct; but this works too)
    }
    echo$u[]=$v,'
';
}
#echo '</pre>';} // FUNC