30
\$\begingroup\$

The six main cast members of the American sitcom Friends all agreed that they would be paid the same salary throughout the run of the series (after season 2, at least). But that doesn't mean that they all had the same amount of air time or that they all interacted on screen with each other the same amount.

In this challenge, you'll write a program that could help determine which Friends friends were really the best.

Setup

Consider watching an episode or scene of Friends and noting down exactly who is on screen during each camera shot and for how long.

We'll abbreviate each character's name:

Then for every camera shot (or every time a character enters/exits the shot), we'll list who was on screen. For example:

504 CRS
200 J
345 MP
980
2000 CJMPRS

This is saying that:

  • For 504ms, Chandler, Rachel, and Ross were on screen.
  • Then for 200ms, Joey was.
  • Then for 345ms, Monica and Phoebe were.
  • Then for 980ms, none of the 6 main characters were on screen.
  • Then for 2 seconds, all of them were.

(This is not from an actual clip, I made it up.)

Note that the following would be equivalent:

504 CRS
1 J
199 J
345 MP
980
2000 CJMPRS

To analyze which combinations of characters had the most screen time, we look at all 64 possible subsets of the 6 characters and total up the screen time they had. If everyone in a subset appears on screen during a camera shot, even if there are more characters than just the ones in the subset, the time for that camera shot is added to that subset's total screen time.

There's an exception for the empty subset - only the scenes with none of the 6 main characters are counted.

So the analysis of the example above would be:

980
2504 C
2200 J
2345 M
2345 P
2504 R
2504 S
2000 CJ
2000 CM
2000 CP
2504 CR
2504 CS
2000 JM
2000 JP
2000 JR
2000 JS
2345 MP
2000 MR
2000 MS
2000 PR
2000 PS
2504 RS
2000 CJM
2000 CJP
2000 CJR
2000 CJS
2000 CMP
2000 CMR
2000 CMS
2000 CPR
2000 CPS
2504 CRS
2000 JMP
2000 JMR
2000 JMS
2000 JPR
2000 JPS
2000 JRS
2000 MPR
2000 MPS
2000 MRS
2000 PRS
2000 CJMP
2000 CJMR
2000 CJMS
2000 CJPR
2000 CJPS
2000 CJRS
2000 CMPR
2000 CMPS
2000 CMRS
2000 CPRS
2000 JMPR
2000 JMPS
2000 JMRS
2000 JPRS
2000 MPRS
2000 CJMPR
2000 CJMPS
2000 CJMRS
2000 CJPRS
2000 CMPRS
2000 JMPRS
2000 CJMPRS

We can see that J (just Joey) had 2200ms of screen time because he had 200 by himself and 2000 with everyone.

Challenge

Write a program that takes in a string or text file such as

504 CRS
200 J
345 MP
980
2000 CJMPRS

where each line has the form [time in ms] [characters on screen], and outputs the total amount of time that each of the 64 subsets of the 6 characters spent on the screen, where each line has the form [total time in ms for subset] [characters in subset] (just as above).

The input can be taken as a string to stdin, the command line, or a function, or it can be the name of a text file that contains the data.

  • The milliseconds numbers will always be positive integers.
  • The character letters will always be in the order CJMPRS (alphabetical).
  • You can optionally assume there is a trailing space when there are no characters in the scene (e.g. 980 ).
  • You can optionally assume there is a trailing newline.
  • The input will have at least 1 line and may have arbitrarily many.

The output should be printed or returned or written to another text file as a 64 line string.

  • The lines may be in any order.
  • The character letters do not need to be in the CJMPRS order.
  • Subsets with 0ms total time do need to be listed.
  • There may optionally be a trailing space after the empty subset total.
  • There may optionally be a trailing newline.

(This problem can of course be generalized to more characters, but we'll stick with the 6 CJMPRS Friends characters.)

The shortest code in bytes wins.

Note that I actually enjoy Friends and don't think some characters are more important than the others. The statistics would be interesting though. ;)

\$\endgroup\$
6
  • 7
    \$\begingroup\$ Do we get a bounty if we post an analysis of the series? ;) \$\endgroup\$
    – Beta Decay
    Jul 7, 2015 at 9:28
  • 5
    \$\begingroup\$ I may or may not have seen every episode dozens of times and own all 10 seasons... \$\endgroup\$
    – Alex A.
    Jul 7, 2015 at 13:01
  • \$\begingroup\$ @AlexA. I may or may not know what you are talking about... \$\endgroup\$
    – bolov
    Jul 7, 2015 at 17:28
  • \$\begingroup\$ The empty set is a special case — it doesn't obey the "even if there are more characters than just the ones in the subset" rule, or else it would score 4029 in the example (the total amount of time that at least no one is on screen), and not 980. \$\endgroup\$
    – hobbs
    Jul 7, 2015 at 18:53
  • 1
    \$\begingroup\$ @BetaDecay Quite possibly, actually! \$\endgroup\$ Jul 7, 2015 at 20:03

7 Answers 7

13
\$\begingroup\$

Haskell, 187 bytes

f=g.(>>=(q.words)).lines
g t=p"CJMPRS">>=(\k->show(sum.map snd$filter((==k).fst)t)++' ':k++"\n")
q[n]=[("",read n)]
q[n,s]=[(k,read n)|k<-tail$p s]
p s=map concat$sequence[[[],[c]]|c<-s]

f is a function that takes the input, as a single multi-line string, and returns the multi-line output as single string. Probably plenty left to golf here.

λ: putStr test1
504 CRS
1 J
199 J
345 MP
980
2000 CJMPRS

λ: putStr $ f test1
980 
2504 S
2504 R
2504 RS
2345 P
2000 PS
2000 PR
2000 PRS
2345 M
2000 MS
2000 MR
2000 MRS
2345 MP
2000 MPS
2000 MPR
2000 MPRS
2200 J
2000 JS
2000 JR
2000 JRS
2000 JP
2000 JPS
2000 JPR
2000 JPRS
2000 JM
2000 JMS
2000 JMR
2000 JMRS
2000 JMP
2000 JMPS
2000 JMPR
2000 JMPRS
2504 C
2504 CS
2504 CR
2504 CRS
2000 CP
2000 CPS
2000 CPR
2000 CPRS
2000 CM
2000 CMS
2000 CMR
2000 CMRS
2000 CMP
2000 CMPS
2000 CMPR
2000 CMPRS
2000 CJ
2000 CJS
2000 CJR
2000 CJRS
2000 CJP
2000 CJPS
2000 CJPR
2000 CJPRS
2000 CJM
2000 CJMS
2000 CJMR
2000 CJMRS
2000 CJMP
2000 CJMPS
2000 CJMPR
2000 CJMPRS
\$\endgroup\$
10
\$\begingroup\$

Pyth, 37 bytes

Vy"CJMPRS"++smvhdf?q@eTNNN!eTcR\ .zdN

Try it online: Demonstration

Explanation:

  "CJMPRS"                             string with all friends
 y                                     create all subsets
V                                      for loop, N iterates over ^:
                                 .z      all input lines
                             cR\         split each line at spaces
                 f                       filter for lines T, which satisfy:
                  ?      N                 if N != "":
                   q@eTNN                    intersection(T[1],N) == N
                                           else:
                          !eT                T[1] == ""
             m                           map each of the remaining d to:
              vhd                          eval(d[0]) (extract times)
            s                            sum
           +                       d     + " "
          +                         N    + N
                                         implicitly print
\$\endgroup\$
6
  • \$\begingroup\$ It's hardly even worth trying when I write one line of my solution and it's already longer than the whole Pyth answer :-P \$\endgroup\$
    – hobbs
    Jul 7, 2015 at 18:35
  • 4
    \$\begingroup\$ @hobbs That's the downside of mixed language competitions. But don't be intimidated, solutions in other languages usually receive more votes. Just look at the Haskell-Solution. \$\endgroup\$
    – Jakube
    Jul 7, 2015 at 18:39
  • 3
    \$\begingroup\$ 36% shorter and made me realize I had a bug in my code... \$\endgroup\$
    – Dennis
    Jul 7, 2015 at 18:55
  • \$\begingroup\$ It's rather unfortunate that cM uses the .* map expansion. Perhaps an exception should be made for c as I can't imagine someone wanting to use it like that in a map \$\endgroup\$ Jul 7, 2015 at 21:37
  • \$\begingroup\$ This gives 0 on the top line in the example output instead of 980. \$\endgroup\$ Sep 22, 2015 at 22:10
7
\$\begingroup\$

SWI-Prolog, 381 bytes

s([E|T],[F|N]):-E=F,(N=[];s(T,N));s(T,[F|N]).
a(A):-split_string(A," \n","",B),w(B,[],C),setof(L,s(`CJMPRS`,L),M),x(C,[` `|M]).
w([A,B|T],R,Z):-number_string(N,A),(B="",C=` `;string_codes(B,C)),X=[[N,C]|R],(T=[],Z=X;w(T,X,Z)).
x(A,[M|T]):-y(M,A,0,R),atom_codes(S,M),writef("%t %w\n",[R,S]),(T=[];x(A,T)).
y(_,[],R,R).
y(M,[[A,B]|T],R,Z):-subset(M,B),S is R+A,y(M,T,S,Z);y(M,T,R,Z).

This expects to be run as:

a("504 CRS
200 J
345 MP
980 
2000 CJMPRS").

Note that you might need to replace every ` to " and every " to ' if you have an old version of SWI-Prolog.

I could shave off 100+ bytes if I didn't have to use a String as an input.

\$\endgroup\$
7
\$\begingroup\$

Haskell, 150 136 bytes

import Data.List
f=(subsequences"CJMPRS">>=).g
g l c=show(sum[read x|(x,y)<-map(span(/=' '))$lines l,c\\y==[],c/=[]||c==y])++' ':c++"\n"

Usage example:

*Main> putStr $ f "504 CRS\n1 J\n199 J\n345 MP\n980\n2000 CJMPRS"
980 
2504 C
2200 J
2000 CJ
2345 M
2000 CM
2000 JM
2000 CJM
2345 P
2000 CP
2000 JP
2000 CJP
2345 MP
2000 CMP
2000 JMP
2000 CJMP
2504 R
2504 CR
2000 JR
2000 CJR
2000 MR
2000 CMR
2000 JMR
2000 CJMR
2000 PR
2000 CPR
2000 JPR
2000 CJPR
2000 MPR
2000 CMPR
2000 JMPR
2000 CJMPR
2504 S
2504 CS
2000 JS
2000 CJS
2000 MS
2000 CMS
2000 JMS
2000 CJMS
2000 PS
2000 CPS
2000 JPS
2000 CJPS
2000 MPS
2000 CMPS
2000 JMPS
2000 CJMPS
2504 RS
2504 CRS
2000 JRS
2000 CJRS
2000 MRS
2000 CMRS
2000 JMRS
2000 CJMRS
2000 PRS
2000 CPRS
2000 JPRS
2000 CJPRS
2000 MPRS
2000 CMPRS
2000 JMPRS
2000 CJMPRS

Different approach than @MtnViewMark's answer: For all combinations c of the characters find the lines of the input string where the difference of c and the list from the lines y is empty (take care of the special case where no character is on screen (e.g. 980) -> c must be not empty or c == y). Extract the number and sum.

\$\endgroup\$
6
\$\begingroup\$

CJam, 67 58 bytes

"CJMPRS"6m*_.&:$_&qN/_{_el=},:~1bpf{{1$\-!},Sf/0f=:i1bS\N}

Try it online in the CJam interpreter.

\$\endgroup\$
2
\$\begingroup\$

Perl 5 (5.10+), 128 bytes

2 bytes per line of output. use feature "say" not included in the byte count.

@_=<>;for$i(0..63){@c=qw(C J M P R S)[grep$i&(1<<$_),0..5];
$r=@c?join".*","",@c:'$';$t=0;for(@_){$t+=$1 if/(.*) $r/}say"$t ",@c}

Un-golfed:

# Read the input into an array of lines.
my @lines = <>;
# For every 6-bit number:
for my $i (0 .. 63) {
    # Select the elements of the list that correspond to 1-bits in $i
    my @indices = grep { $i & (1 << $_) } 0 .. 5;
    my @characters = ('C', 'J', 'M', 'P', 'R', 'S')[@indices];

    # Build a regex that matches a string that contains all of @characters
    # in order... unless @characters is empty, then build a regex that matches
    # end-of-line.
    my $regex = @characters
      ? join ".*", ("", @c)
      : '$';

    my $time = 0;
    # For each line in the input...
    for my $line (@lines) {
        # If it contains the requisite characters...
        if ($line =~ /(.*) $regex/) {
            # Add to the time total
            $time += $1;
        }
    }

    # And print the subset and the total time.
    say "$time ", @characters;
}
\$\endgroup\$
2
\$\begingroup\$

K, 95

{(+/'{x[1]@&min'y in/:*x}[|"I \n"0:x]'b)!b:" ",?,/{x{,/y{x,/:y@&y>max x}\:x}[d]/d:"CJMPRS"}

Takes a string like "504 CRS\n200 J\n345 MP\n980 \n2000 CJMPRS"

k){(+/'{x[1]@&min'y in/:*x}[|"I \n"0:x]'b)!b:" ",?,/{x{,/y{x,/:y@&y>max x}\:x}[d]/d:"CJMPRS"}["504 CRS\n200 J\n345 MP\n980  \n2000 CJMPRS"]
980 | " "
2504| "C"
2200| "J"
2345| "M"
2345| "P"
2504| "R"
2504| "S"
2000| "CJ"
2000| "CM"
2000| "CP"
2504| "CR"
2504| "CS"
2000| "JM"
2000| "JP"
2000| "JR"
2000| "JS"
2345| "MP"
2000| "MR"
2000| "MS"
2000| "PR"
2000| "PS"
2504| "RS"
2000| "CJM"
2000| "CJP"
2000| "CJR"
2000| "CJS"
2000| "CMP"
2000| "CMR"
2000| "CMS"
2000| "CPR"
2000| "CPS"
2504| "CRS"
2000| "JMP"
2000| "JMR"
2000| "JMS"
2000| "JPR"
2000| "JPS"
2000| "JRS"
2000| "MPR"
2000| "MPS"
2000| "MRS"
2000| "PRS"
2000| "CJMP"
2000| "CJMR"
2000| "CJMS"
2000| "CJPR"
2000| "CJPS"
2000| "CJRS"
2000| "CMPR"
2000| "CMPS"
2000| "CMRS"
2000| "CPRS"
2000| "JMPR"
2000| "JMPS"
2000| "JMRS"
2000| "JPRS"
2000| "MPRS"
2000| "CJMPR"
2000| "CJMPS"
2000| "CJMRS"
2000| "CJPRS"
2000| "CMPRS"
2000| "JMPRS"
2000| "CJMPRS"
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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