# Heterograms, Palindromes, oh my!

(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 :)

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

# 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

• Jeez, and I was worried that this would be too hard... Nice job! Sep 24, 2015 at 16:15
• You have a .q in your comments, but a .w in your program. Sep 25, 2015 at 7:31
• @JamesWebster Thanks for pointing that out. It should be .q Sep 25, 2015 at 17:59

# 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

• Very minor point, but from the rules you should change the second < into a >! Sep 24, 2015 at 22:25

# Perl, 43 bytes

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


Usage example:

echo "abcde" | perl -n entry.pl

• Wow, that's amazing. Nice job! Sep 24, 2015 at 22:18

# Pyth - 11 bytes

(Trailing and leading spaces necessary and counted).

 z.{ z }.z

<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

• Mike's Pyth answer converts to lowercase before doing .{, are you sure you don't need to do that too? Dec 6, 2016 at 2:54

## ><>, 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  • Glad to see a ><> answer :) Sep 25, 2015 at 13:42 • Also, ><> is a palindrome itself (just not a convenient one) – Jo King Mar 2, 2019 at 11:31 ## 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

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

# 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.

• "Non-competing since 05AB1E was made before this challenge." Perhaps you meant after this challenge? ;) Nov 3, 2016 at 15:04

# 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.

# 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.


# 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