28
\$\begingroup\$

(First challenge, please let me know if there are any problems with it.)

A heterogram is a word where no letter of the alphabet occurs more than once, and a palindrome is a phrase that is the same backwards and forwards.

The challenge here is to write a piece of code that takes in a word (just letters) as input, and outputs whether or not it is a heterogram (truthy/falsy). The catch is that the program must be a palindrome -- reads the same backwards and forwards. Capitalization doesn't matter here, so for the heterogram to be valid it can't have both q and Q, for instance. No comments are allowed, and you cannot place strings that contain your code (or a significant part of your code) to try to make the palindrome part easy :P

This is code-golf, so shortest code wins. Good luck!

EDIT: Parens, brackets or other symbols that have left and right forms must be reversed approriately for the palindrome part. So (helloolleh) is a palindrome, but (helloolleh( is not. Apparently this is called a convenient palindrome.

EDIT 2: You won't get any empty input, input with multiple words or input with characters other than letters. So don't worry about that :)

\$\endgroup\$
  • \$\begingroup\$ Are brackets considered to be equivalent for palindromicity? That is, is (hellolleh) a valid palindrome? Similar for [], {}, and <> (where appropriate). \$\endgroup\$ – Glen O Sep 24 '15 at 15:11
  • \$\begingroup\$ Yes. Sorry, I should have explained that. \$\endgroup\$ – a spaghetto Sep 24 '15 at 15:21
  • \$\begingroup\$ What about new lines, will asdsa be considered equal to asd\nsa? \$\endgroup\$ – wendelbsilva Sep 24 '15 at 15:42
  • \$\begingroup\$ No, they would not be equivalent. \$\endgroup\$ – a spaghetto Sep 24 '15 at 16:01
  • 5
    \$\begingroup\$ I believe it's called a convenient palindrome. \$\endgroup\$ – lirtosiast Sep 24 '15 at 22:36

10 Answers 10

9
\$\begingroup\$

Pyth - 11 bytes

(Trailing and leading spaces necessary and counted).

 z.{ z }.z 

Test Suite.

<space>        Suppress print
 z             Input (for palindromness)
.{             Unique - actually does testing
  z            Input
<space>        Suppress print
  }            In operator
   .z          Cached input list
   <space>     At end of program makes empty tuple
\$\endgroup\$
  • \$\begingroup\$ Mike's Pyth answer converts to lowercase before doing .{, are you sure you don't need to do that too? \$\endgroup\$ – Sparr Dec 6 '16 at 2:54
18
\$\begingroup\$

Pyth, 17 bytes

 Z.{rzZ.q.Zzr}.Z 

Try it online here.

The leading space is necessary. I have counted it and the trailing space in the byte count.

Here's the breakdown:

     z            z is initialized to the input
    r Z           Z is initialized to 0, and r(string)0 converts the string to lowercase
  .{              .{ is pyth's builtin uniqueness test
       .q         .q terminates the program
         .Zzr}    This is just the program mirrored
              .Z  . requires a number to immediately follow it
                  If left blank the parser would throw an error
 Z                This is just mirrored from the end
                  The leading space suppresses the automatic printing of this 0
                  The trailing space mirrors the leading space
\$\endgroup\$
  • 3
    \$\begingroup\$ Jeez, and I was worried that this would be too hard... Nice job! \$\endgroup\$ – a spaghetto Sep 24 '15 at 16:15
  • 2
    \$\begingroup\$ You have a .q in your comments, but a .w in your program. \$\endgroup\$ – James Webster Sep 25 '15 at 7:31
  • \$\begingroup\$ @JamesWebster Thanks for pointing that out. It should be .q \$\endgroup\$ – Mike Bufardeci Sep 25 '15 at 17:59
16
\$\begingroup\$

Python 3, 125

The main problem is to make the reverse of the code parsable. Then we can let it error out from undefined identifiers.

w=[str.lower][0]((input)())
(print)((max)((map)(w.count,w))<2)
(2>((w,tnuoc.w)(pam))(xam))(tnirp)
(()(tupni))[0][rewol.rts]=w
\$\endgroup\$
  • \$\begingroup\$ Very minor point, but from the rules you should change the second < into a >! \$\endgroup\$ – Jarmex Sep 24 '15 at 22:25
12
\$\begingroup\$

Perl, 43 bytes

print+m:^(?!.*(.).*\1|1/*.(.)*.!?)^:m+tnirp

Usage example:

echo "abcde" | perl -n entry.pl
\$\endgroup\$
  • \$\begingroup\$ Wow, that's amazing. Nice job! \$\endgroup\$ – a spaghetto Sep 24 '15 at 22:18
6
\$\begingroup\$

><>, 137 131 Bytes

When I saw this challenge, I thought ><> might finally be a good choice of language since using it you can mostly ignore palindromes; it is simple to make sure the pointer only stays where it should. While this is true, ><> unfortunately makes golfing conditionals excruciating (or just golfing in general). I hope to use some weird tricks I thought of to compensate for this, but here's a "quick" (not actually, both program-wise and creation-wise) answer. You can try it online here.

i:0(?v>:"Z")?vl1-:1(?v&:{:@=?v$&e0.>
  ;n1<^  -*48<   .00~<  ;n-10<01-n;  >~00.   >84*-  ^>1n;
<.0e&$v?=@:}:&v?)1:-1lv?("Z":<v?)0:i

Returns 1 for true and -1 for false (I could change it to 0 but the length would stay the same, unfortunately)

As always, let me know if this doesn't work and if you have any ideas on how to golf it down. I tested it against a few test cases, but there always could be an exception.

Here's another version, one that I think is a bit more clever, but alas is ten bytes more. Truthy/falsey values this time are 1 and an error (something smells fishy...):

>i:0(?v>:"Z")?vl: 2(?v&{:@$:@=01-*2.
 < ;n1<^  -*48<f6+0.0<
 &1-:1)e*1.1*e(1:-1& 
>0.0+6f>84*-  ^>1n; > 
.2*-10=@:$@:}&v?)2 :lv?("Z":<v?)0:i<

Explanation:

Here's the code without the part added to make it a palindrome. This one doesn't use the "more clever" tricks I attempted to use for the alternate version, so it's a bit easier to explain (if anyone is interested in an explanation for the "tricks," I'd be happy to give one, though).

i:0(?v>:"Z")?vl1-:1(?v&:{:@=?v$&e0.>
  ;n1<^  -*48<   .00~<  ;n-10<

Line 1:

i:0(?v>:"Z")?vl1-:1(?v&:{:@=?v$&e0.>
i:0(?v                                 #Pushes input and directs down if negative
      >:"Z")?v                         #Directs down if input is greater than "Z"
                                       #(reduces lowercase input to uppercase)
              l                        #Pushes length

                                       #Main loop begins
               1-:1(?v                 #Decrements top, and then directs down if less than 1
                      &                #Pushes top of stack onto register (length minus 1)
                       :{              #Duplicates top, shifts stack to the left
                         :@            #Duplicates top, shifts top three values of the stack to the right

                           =?v         #If top two values are equal, directs down
                              $        #Swaps top two values of the stack
                               &       #Pushes register onto stack
                                e0.    #Jumps back to the "1" after "?vl"
                                       #Main loop ends

                                   >   #Makes sure when the pointer jumps back to i it goes the right way

Here's how the convoluted swapping (:{:@=?v$) works -- I'll use a test case of this stack: [5,1,8,1] where the last character is the top.

:{ The top of the stack is duplicated: [5,1,8,1,1], and the stack shifted to the left: [1,8,1,1,5]

:@ The top is duplicated: [1,8,1,1,5,5], then the top three values are shifted to the right: [1,8,1,5,1,5]

=?v Unnecessary for this part of explanation

$ The top value is swapped once more yielding [1,8,1,5], which, if you'll note, is the original stack shifted over once (as if { had been the only command).


So what this does in English ("Thank God, he's actually explaining things") is check the entire stack against the top value and move to a point in the second line if any value equals the top. This checking is done proportionate to how many values there are in the stack (l - 1, where l is the length of the stack) so that all values are checked against each other.

Line 2:

  ;n1<^  -*48<   .00~<  ;n-10<
   n1<                          #If input is less than 0 (i.e. there is none), print 1
  ;                             #and terminate

             <                  #If redirected because input is greater than "Z"
         -*48                   #Push 32, subtract (reducing lowercase to uppercase, numerically)
      ^                         #And move back to the portion that tests if input 
                                #is uppercase (which it will pass now)

                     <          #If counter is less than 1 (for main loop)
                 .00~           #Pop the counter and jump to the beginning (i)

                             <  #If any two values in the stack are equal
                          -10   #Push -1 (subtract 1 from 0)
                        ;n      #Print and terminate
\$\endgroup\$
  • \$\begingroup\$ Glad to see a ><> answer :) \$\endgroup\$ – a spaghetto Sep 25 '15 at 13:42
  • 1
    \$\begingroup\$ Also, ><> is a palindrome itself (just not a convenient one) \$\endgroup\$ – Jo King Mar 2 at 11:31
5
\$\begingroup\$

PHP, 126 Bytes

You need to run this with the short_tags ini directive turned off in 5.4 or above.

First golf ever. Two copies, the first prints a whole bunch of garbage with the falsy/truthy result:

<?=var_dump(max(array_count_values(str_split(end($argv))))<2)?><?(2>((((vgra$)dne)tilps_rts)seulav_tnuoc_yarra)xam)pmud_rav=?>

This version will not print any jargon (162 bytes):

<?=var_dump(max(array_count_values(str_split(end($argv))))<2);__halt_compiler()?><?()relipmoc_tlah__;(2>((((vgra$)dne)tilps_rts)seulav_tnuoc_yarra)xam)pmud_rav=?>

Run from the command line with

php -f golf.php heterogram

Probably can be golfed a bit further

\$\endgroup\$
  • \$\begingroup\$ Clever, though pushing limits of validness. Maybe for the sport think of a solution with comments \$\endgroup\$ – Martijn Sep 25 '15 at 11:24
  • \$\begingroup\$ Instead of ?><?, you can use //\\. That should remove that requirement. And instead of __halt_compiler() use return; \$\endgroup\$ – Ismael Miguel Sep 25 '15 at 11:24
  • \$\begingroup\$ Disregard it. You can't use comments. But the return; is still valid. \$\endgroup\$ – Ismael Miguel Sep 25 '15 at 11:47
2
\$\begingroup\$

05AB1E, 9 bytes

lDÙQqQÙDl

Try it online.

*insert something about going all the way back to my very first challenge*

Non-competing since 05AB1E was made after this challenge.

Explanation

lDÙQqQÙDl
l           Take input and lowercase it.
 DÙ         Duplicate and uniquify.
   Q        Compare the two strings.
    q       Immediately exit.
     QÙDl   The rest of the program is ignored.
\$\endgroup\$
  • 1
    \$\begingroup\$ "Non-competing since 05AB1E was made before this challenge." Perhaps you meant after this challenge? ;) \$\endgroup\$ – ETHproductions Nov 3 '16 at 15:04
2
\$\begingroup\$

Brachylog, 3 bytes, language postdates challenge

DdD

Try it online!

This is one of the very few programs that works in both Brachylog 1 and Brachylog 2. The TIO link is to Brachylog 1 for old times' sake. Also unsually for Brachylog, this is a full program, not a function. (Full programs in Brachylog implicitly output booleans, which is just what we want for this question.)

The general principle here is that placing a predicate between a pair of identical uppercase letters is an assertion that the current value is invariant under that predicate. So you often see things like AoA for "is sorted" ("invariant under sorting"); A↔A would (in Brachylog 2) mean "is a palindrome" ("invariant under reversal"), and so on. This program is "invariant under removing duplicates", i.e. "doesn't contain duplicates". It's really convenient that this method of specifying invariance happens to be a palindrome.

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

Brachylog, 3 bytes

≠ụ≠

Try it online!

The predicate succeeds if the input is a heterogram and fails if it is not.

≠      The characters of the input are all distinct,
 ụ     and when converted to upper case,
  ≠    are still all distinct.
\$\endgroup\$
0
\$\begingroup\$

MATL, 7 bytes

tuX=Xut

Try it online!

Returns list [1, 1] if the input is a heterogram and [0, 0] if not.

Explanation:

t       % duplicate the input
u       % remove duplicates from the original
X=      % check the two lists are equal
Xu      % unique rows (does nothing as we now have a boolean)
t       % duplicate the result
        % (implicit) convert to string and display
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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