9
\$\begingroup\$

Given two lists that contain no duplicate elements a and b, find the crossover between the two lists and output an ASCII-Art Venn Diagram. The Venn Diagram will use a squarified version of the traditional circles for simplicity.

Example

Given:

a = [1, 11, 'Fox', 'Bear', 333, 'Bee']
b = ['1', 333, 'Bee', 'SchwiftyFive', 4]

Output (Order is 100% arbitrary, as long as the Venn Diagram is correct):

+-----+----+-------------+
|11   |333 |SchwiftyFive |
|Fox  |Bee |4            |
|Bear |1   |             |
+-----+----+-------------+

The program may either consider '1' == 1 or '1' != 1, up to your implementation. You may also choose to just handle everything as strings, and only accept string input.


Given:

a=[]
b=[1,2,3]

Output (Notice how the two empty parts still have the right-pad space):

+-+-+--+
| | |1 |
| | |2 |
| | |3 |
+-+-+--+

Given:

a=[1]
b=[1]

Output:

+-+--+-+
| |1 | |
+-+--+-+

Rules

  • Elements of the Venn Diagram are left-aligned and padded to the max length entry plus 1.
  • The ordering of the elements within sub-sections of the Venn-Diagram are arbitrary.
  • Corners of the Venn Diagram (where | meets -) must be represented by a +.
  • You are garuanteed that a.join(b).length() > 0, if both are empty, you may do whatever.
    • You may even print a picture of Abe Lincoln, don't care.
  • This is , and .

Bonus

Charcoal renders boxes like this naturally, but the whole set theory part... Don't know how well it does that. +100 bounty for the shortest charcoal submission before I am able to add a bounty to the question (2 days from being asked).

\$\endgroup\$
7
  • 3
    \$\begingroup\$ Personally, I feel that being able to support '1' == 1 is a bit too much of a stretch \$\endgroup\$
    – user41805
    May 11, 2017 at 19:07
  • \$\begingroup\$ @KritixiLithos fair enough, updated the challenge spec so that it doesn't hurt those who have started. It is now your choice on how you want string to integer comparison to work, both choices being equally valid submissions. \$\endgroup\$ May 11, 2017 at 19:09
  • 1
    \$\begingroup\$ Can we assume that the input will only contain strings? \$\endgroup\$
    – Rod
    May 11, 2017 at 19:10
  • \$\begingroup\$ Related. \$\endgroup\$ May 11, 2017 at 19:12
  • 2
    \$\begingroup\$ @L3viathan one mobile edit and your post is over. \$\endgroup\$ May 11, 2017 at 22:13

5 Answers 5

5
\$\begingroup\$

Husk, 72 58 bytes

mṙ1₁Fz+m(₁TT' Ṡ:→S:öR'-→▲mL)TTømėF`-FnF-
Ṡz:(`:'+:'+R'|-2L

Try it online!

Husk does not support arrays of multiple types, so the arguments must be string arrays.

I am not sure whether I want to explain this monstrosity.

Due to it's sheer size, it takes about 28 secs(due to type inference) for the first test case mentioned. Without some of the type inference issues, this could be a lot shorter.

-14 bytes with a lot of adjustments(I got better at Husk).

\$\endgroup\$
3
  • \$\begingroup\$ FYI Charcoal could be as low as 48 bytes if I used implicit input: Try it online! \$\endgroup\$
    – Neil
    Feb 1, 2021 at 1:12
  • \$\begingroup\$ woah why not use that \$\endgroup\$
    – Razetime
    Feb 1, 2021 at 2:38
  • 1
    \$\begingroup\$ I was only here for Best of 2020; I don't normally bother editing very old answers, and I'd now need to beat 47 anyway. \$\endgroup\$
    – Neil
    Feb 1, 2021 at 10:40
3
\$\begingroup\$

Charcoal, 106 89 87 bytes:

A⟦⟧ςA⟦⟧λA⟦⟧ρA⟦⟧τWS⊞ςιWS⊞⎇№ςιτριFς⊞⎇№τι⟦⟧λιF⟦λτρ⟧«Fι«↓Pκ»MLι↑←A⁺⌈EιLκ³ζURζ⁺⌈⟦LλLτLρ⟧²Mζ→

Try it online! Note that link is to verbose code for explanatory purposes, with the -sl option that shows the equivalent native Charcoal code. Takes input as newline-separated strings with a blank line after each set.

Edit: Saved 11 bytes thanks to @ASCII-only. Previous version actually had a bug when the last word in the first set was not in the second set and also the first column was the tallest, which manifested as an apparently inability to optimise away a temporary. Saved 2 bytes by optimising two Move commands (the deverbosifier now does this automatically but the resulting code was always valid so the answer is still competing).

Edit: I don't think Multiprint used to work with multiline output but it does currently and making use of that would save 6 bytes, plus a further 4 bytes because current Charcoal preinitialises the u variable to the empty list: Try it online!

\$\endgroup\$
7
  • \$\begingroup\$ Oh, if you want to print without moving the cursor, use Multiprint () \$\endgroup\$
    – ASCII-only
    May 11, 2017 at 22:45
  • \$\begingroup\$ Okay, 95 bytes, remember to remove commas/semicolons to remove delimiter in non-verbose form (will fix later), also Map exists (sorry, will document asap) \$\endgroup\$
    – ASCII-only
    May 11, 2017 at 23:29
  • \$\begingroup\$ @ASCII-only Huh, well, I'm sure I tried Multiprint at some point, so I don't know why I wasn't able to get it to work. Also, thanks for Map, it helped me optimise the answer a bit more. Finally, I think Charcoal sometimes lets you use without an which would save a byte here, or is that a bug? \$\endgroup\$
    – Neil
    May 12, 2017 at 0:10
  • \$\begingroup\$ Directions without an are intentional (but always remember a direction with a variable after is a directional print) \$\endgroup\$
    – ASCII-only
    May 12, 2017 at 0:14
  • 1
    \$\begingroup\$ Okay, done, now all we need to do is wait for Dennis to pull for the better Move deverbosifying (it also now removes more unneeded separators so you'll be able to add the commas back in if you want) \$\endgroup\$
    – ASCII-only
    May 12, 2017 at 0:43
2
\$\begingroup\$

Python 2, 221 210 212 bytes

m=map
A,B=m(set,input())
d=A-B,B&A,B-A
e=[max(m(len,s))+1for s in d]
p,i,n='+|\n'
o=b=p+p.join(m('-'.__mul__,e))+p+n
while sum(m(len,d)):o+=i+i.join(m(str.ljust,[len(s)and s.pop()or''for s in d],e))+i+n
print o+b

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Slightly wrong, you're missing the one space char right-pad. \$\endgroup\$ May 11, 2017 at 20:40
  • \$\begingroup\$ @carusocomputing fixed \$\endgroup\$
    – Rod
    May 11, 2017 at 21:41
2
\$\begingroup\$

PHP>=7.1, 287 Bytes

<?for([$a,$b]=$_GET,$x=max(($m=array_map)(count,$r=[($d=array_diff)($a,$b),array_intersect($a,$b),$d($b,$a)]));$n<3;$n++)for(sort($r[+$n]),$i=-1;$i<=$x;$i++){$o[$i].="|+"[$b=$i<0||$i==$x].str_pad($b?"":$r[+$n][$i],max($m(strlen,$r[+$n]))+1," -"[$b]).("|+"[$b][$n<2]);}echo join("
",$o);

Online Version

Expanded

for([$a,$b]=$_GET, # store input arrays in shorter variables
$x=max(($m=array_map)(count,   # get maximum of 
$r=[($d=array_diff)($a,$b),array_intersect($a,$b),$d($b,$a)])); #the set array
$n<3;$n++)
  for(sort($r[+$n]),$i=-1;$i<=$x;$i++){ # sort array to remove keys
    $o[$i].="|+"[$b=$i<0||$i==$x].   # concat line $b boolean for first and last line beginning char 
    str_pad($b?"":$r[+$n][$i]   # string of item in array if not first or last line
    ,max($m(strlen,$r[+$n]))+1  # fill till maximum length of items in array
    ," -"[$b]) # with char depends on first/last line or item line
    .("|+"[$b][$n<2]); # make end of string if last array is reach
}
echo join("   
",$o); #Output
\$\endgroup\$
1
\$\begingroup\$

05AB1E, 47 bytes

ʒå}©K®¹®Kr)õζ'|ìøε€SζøJ}ø'|δªðý¬„|+`:D¬мS'-:.ø»

Try it online or verify all test cases.

Explanation:

ʒ               # Filter the first (implicit) input-list by:
 å              #  Check if the current item is in the second (implicit) input-list
}©              # After the filter: store this overlap in variable `®` (without popping)
  K             # Pop and remove those items from the second (implicit) input-list
®               # Push overlap `®`
¹               # Push the first input-list again
 ®K             # Remove overlap `®`
r               # Reverse the three lists on the stack
 )              # And wrap them into a list
 ζ              # Zip/transpose this list, swapping rows/columns,
õ               # with "" as filler if the lists are of unequal length
  '|ì          '# Prepend an "|" in front of each inner string
ø               # Zip/transpose back, swapping rows/columns
 ε              # Map over each row:
  €             #  Map over each string in this row:
   S            #   Convert it to a list of characters
    ζ           #  Zip/transpose, swapping rows/columns, with " " as default filler
     ø          #  And then zip/transpose back
      J         #  And join the strings back together
 }ø             # After the map: zip/transpose back
  δ             # Map over each row:
'| ª           '#  And append an "|" to it
    ðý          # Then join each inner-most list by spaces
¬               # Push the first row (without popping the list)
 „|+`:          # Replace all "|" with "+"
      D         # Duplicate this string
       ¬        # Push its first characters (without popping), which is a "+"
        м       # Remove all "+" from the duplicated string
         S      # Convert what remains to a list of characters
          '-:  '# Replace each character (except for "+") with "-"
             .ø # Surround the list of rows with this string as leading/trailing items
»               # And finally join the list by newlines
                # (after which the result is output implicitly)
\$\endgroup\$

Your Answer

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

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